Compare commits

..

125 Commits

Author SHA1 Message Date
msb_39367 550ea9ddf9 feature: 添加打包资源
2 months ago
王景 a83f41c883 feat: update package-lock
1 year ago
王景 0237f70511 docs: 添加Node版本描述
1 year ago
ch 24df19af14 Merge branch 'fix/0714-ch'
2 years ago
ch fad9ff6ccb fix:修改服务启动名
2 years ago
ch f360233caa Merge branch 'fix/0714-ch' of https://internel-git.mashibing.cn/yanxuan-frontend/shop-app
2 years ago
ch 0508a6d9df pref:固定端口号
2 years ago
ch 041e15495d fix:下架商品
2 years ago
ch 2a42d55fb6 fix:static地址
2 years ago
ch d1f0e5fbd4 支付回调页面
2 years ago
ch 874340f948 修改打包方式
2 years ago
ch 39f379875b pay
2 years ago
ch 5d8a42f48c pay
2 years ago
ch b59d0698ae clear
2 years ago
ch 194587ba1b fix: 商品已下架
2 years ago
ch 9f195f09b7 fix: 商品已下架
2 years ago
ch a35cb72501 fix:点赞提示,已够吗问题
2 years ago
ch c010790f96 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch f20ced40ad 分页最后一页判断修改
2 years ago
ch 03dab5bd96 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 314f79f2ae 分页最后一页判断修改
2 years ago
ch 24ba55fa25 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 7e7ab987b1 分页最后一页判断修改
2 years ago
ch 5832a43169 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch b3cd9615ca 分页最后一页判断修改
2 years ago
ch fb70e2306f 修改分页判断
2 years ago
ch 0ce97eb86b Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 460ba55458 提交
2 years ago
ch 325bee7e80 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch ffc9769565 修改评论跳转
2 years ago
ch 0ce7d20886 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 4011d2d49c 上传预览
2 years ago
ch 774b4f4064 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 4880836a27 产品验收问题
2 years ago
ch 251d091312 Merge branch 'feature/alipay-0629-ch' into msb_test
2 years ago
ch 987566558d 增长支付订单状态查询
2 years ago
ch ffdb3e549f Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch e0b48c9ea6 fix:修改产品验收问题
2 years ago
ch 1e6de755bd APP支付
2 years ago
ch d4a93fed3d Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch b198706159 取消商家回复
2 years ago
ch 6cc4720315 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 71f9e086d7 评论回复实时显示顺序问题
2 years ago
ch df1a27323d Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 4490d1af99 追评
2 years ago
ch f278d52028 修改标签统计接口Token
2 years ago
ch 0391e24745 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 3e9f8e617e fix:回复长英文显示问题
2 years ago
ch 907bcabad2 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 3739301d83 fix:修改页面刷新全局样式丢失问题
2 years ago
ch 5dc332c05f Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 3d61ca3c1e 修改回复自己用户名
2 years ago
ch 410a721436 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 588a41d196 修改
2 years ago
ch 03e27975b4 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 9722f26b90 fix:评论
2 years ago
ch b2d1f2d9c0 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch f6c4182e68 纯空格不让提交
2 years ago
ch efdf803082 纯空格不让提交
2 years ago
ch e5634eeacb 配置支付宝支付
2 years ago
ch d1ba4b1842 Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 2b3e4a954b config
2 years ago
ch 46a6767afb Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch f11b0ee085 config
2 years ago
ch 96def57eaa Merge branch 'feature/comment-0620-ch' into msb_test
2 years ago
ch 6b2adcaf6a config
2 years ago
ch 2f1332b05d Merge branch 'feature/alipay-0629-ch' into msb_test
2 years ago
ch ec932a429b 支付宝支付
2 years ago
ch 5b6e2d46d2 评论统计不做TK校验
2 years ago
ch a27ce47f65 评论统计不做TK校验
2 years ago
ch 6892041093 修改评论数量
2 years ago
ch a75e6b163c fix:去追评报错
2 years ago
ch 98f910dbe9 fix:评论商品信息跳转到详情
2 years ago
ch 1d3fa277b2 fix:其他评价的页面点击事件
2 years ago
ch ac0fc976ed fix:其他评价的页面点击事件
2 years ago
ch 4e65eeb11a fix: 修复预览相关BUg
2 years ago
ch dd0b6345d5 修改BUg
2 years ago
ch 8f0bc44425 fix:修改点赞
2 years ago
ch 5c62b79812 修改图标
2 years ago
ch 925d13cc40 fix:个人中心添加待评价按钮
2 years ago
ch 90e514436b 修改预览页面
2 years ago
ch 8891cc6734 评价
2 years ago
ch e814e1aa0c Merge branch 'fix/0614-ch' into msb_prod
2 years ago
ch 5aff24319d fix:修改?
2 years ago
ch 47c4d8c11c Merge branch 'fix/0614-ch' into msb_prod
2 years ago
ch c2d0857ca1 fix:消息不显示
2 years ago
ch eacb092b13 feat:修改微信支付参数
2 years ago
ch 017b4da59a fix:会话最后一条消息内容英文强制换行
2 years ago
ch c62a4ec0c9 fix:会话最后一条消息内容英文强制换行
2 years ago
ch c9aa0198ff fix:英文换行
2 years ago
ch bbfb4e3108 fix:英文换行
2 years ago
ch f6fb143a69 解决uui 冲突
2 years ago
ch 226109cdbf fix:update sdk
2 years ago
ch 0d24392296 fix:英文强制换行
2 years ago
ch cdceda6747 fix:退出页面清除当前选中
2 years ago
ch 07f0f61983 fix: 客服转移消息
2 years ago
ch d694741ee1 pref:客服转移提示
2 years ago
ch 9067de54da fix:修改提示消息
2 years ago
ch ae4a4284c9 fix: 在当前会话页面刷新报错问题
2 years ago
ch 99f950804b fix:update im SDK
2 years ago
ch 118282854d fix:update IM SDK
2 years ago
ch e3fd51b216 fix:修改SKD
2 years ago
ch 653bbf90f7 fix: imSdk
2 years ago
ch ecd5c60430 头像 昵称
2 years ago
ch d5ec34c4da fix:删除xxx
2 years ago
ch 71e6293742 fix: IM退出数据清空问题
2 years ago
ch 58657621d9 打包命令退回
2 years ago
ch a29f1065e4 fix: 修改发送商品不显示问题
2 years ago
ch e7c43936f1 添加uuid
2 years ago
ch 5e79d78bfc pref:打包测试
2 years ago
ch c474aa0d26 修改
2 years ago
ch 4ca27cdf8a fix:创建会话未设置当前会话ID
2 years ago
ch daac64b0c9 fix:判断socket打开才创建会话
2 years ago
ch 2df056765f fix: 会话列表展示
2 years ago
ch 0df5bbcc18 fix: 会话ID取错修改
2 years ago
ch 5d795b11b4 取消创建会话调已读
2 years ago
ch 536067e197 添加uuid
2 years ago
ch 51ee94d573 修改SDK
2 years ago
ch 0bdab1c4bf im升级
2 years ago
ch e891706f3d im
2 years ago
ch 317cf6225d fix:分类广告
2 years ago
ch f6bdf195c0 fix: 修复虚拟商品优化问题
2 years ago
ch 02552acb69 fix:调整广告跳转方式判断
2 years ago
ch d6516bbfcf 广告跳转
2 years ago
ch 7e4dd1b9ca pref:页面路由组件文件夹重命名
2 years ago

@ -0,0 +1,3 @@
VUE_APP_BASE_URL = https://k8s-horse-gateway.mashibing.cn
VUE_APP_STATIC_URL = https://k8s-shop-app.mashibing.cn
VUE_APP_IM_URL = wss://k8s-horse-gateway.mashibing.cn

@ -0,0 +1,3 @@
VUE_APP_BASE_URL = https://you-gateway.mashibing.com
VUE_APP_STATIC_URL = https://you-app.mashibing.com
VUE_APP_IM_URL = wss://you-gateway.mashibing.com

@ -0,0 +1,3 @@
VUE_APP_BASE_URL = https://you-gateway.mashibing.com
VUE_APP_STATIC_URL = https://you-app.mashibing.com
VUE_APP_IM_URL = wss://you-gateway.mashibing.com

@ -0,0 +1,3 @@
VUE_APP_BASE_URL = https://k8s-horse-gateway.mashibing.com
VUE_APP_STATIC_URL = https://k8s-shop-app.mashibing.com
VUE_APP_IM_URL = wss://k8s-horse-gateway.mashibing.cn

1
.gitignore vendored

@ -4,6 +4,7 @@ node_modules/
unpackage/ unpackage/
dist/ dist/
.history/ .history/
.hbuilderx/
env.js env.js
yarn.lock yarn.lock

@ -1,16 +0,0 @@
module.exports = {
printWidth: 120,
tabWidth: 4,
useTabs: false,
semi: true,
singleQuote: true,
quoteProps: 'as-needed',
jsxSingleQuote: false,
trailingComma: 'es5',
bracketSpacing: true,
bracketSameLine: false,
arrowParens: 'always',
htmlWhitespaceSensitivity: 'ignore',
vueIndentScriptAndStyle: true,
endOfLine: 'auto',
};

@ -2,72 +2,31 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-17 11:30:06 * @Date: 2022-03-17 11:30:06
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-30 17:19:59 * @LastEditTime: 2022-05-23 21:18:34
* @Description: file content * @Description: file content
--> -->
# shopping-app # shopping-app
严选移动端 严选移动端
## 前置环境
## 技术架构 由于项目依赖问题,开发 `node` 版本必须是 `14` or `16`
- uniapp
- vue2
- unicli
>打包构建工具
- vuex
>状态管理
- uni-simple-router
>路由管理更加的贴近vue-router的路由管理器
- uview-ui
>基础UI库
- js-util-all
>基础工具类
- webscoket
>IM通信
## 规范约束
- 使用 VS Code 进行开发,并安装项目推荐的插件
- 不允许修改 src 目录以外的(项目配置)文件
- 有需要优化解决的问题记录到 TODO.md 文件中,包括技术方面的踩坑记录和业务方面的 BUG 记录
- 按照当前项目结构进行功能开发,不允许随意改变项目文件结构
## 项目结构 如果想安装多个版本,可以通过使用 `nvm` 进行版本管理。然具体安装可以参考下面教程
| SRC 目录 | 用途描述 | [window install nvm](https://juejin.cn/post/7074108351524634655)
| ---------- | ---------------------------- | [mac install nvm](https://juejin.cn/post/7206882855200047161)
| common | 所有JS文件 |
| --api | API 接口定义 |
| --config | 项目内配置文件 |
| --dicts | 项目中的静态字典表 |
| --plugins | 全局插件 |
| --store | 数据状态模块 |
| --utils | 工具类库模块 |
| components | 自定义通用组件 |
| pages | 页面文件 |
| static | 存放应用的本地静态资源的目录 |
## 公共方法 utils
- 公共方法统一放置 utils 文件夹内,可以按分类建方法文件 如:验证类 verify.js 请求类 request.js
## 开发须知
### 路由页面
- 页面代码尽量做业务模块拆分,禁止出现大几百行上千行的页面文件
- 页面业务模块应就在当前页面目录下创建module 不要放到src/components下
### 工具类utils
- 项目集成js-util-all基础组件不需要重复造轮子
- 公共方法统一放置utils文件夹内可以按分类建方法文件 如验证类verify.js 请求类request.js
- 所有公共方法采用大驼峰命名法 - 所有公共方法采用大驼峰命名法
- 所有的方法都从index.js输出引入时统一引入index不允许直接引入方法文件 - 所有的方法都从 index.js 输出,引入时统一引入 index不允许直接引入方法文件
- 所有方法文件如果导出的是多个方法,不允许在定义方法时导出,必须在文件底部一一导出,并附上方法简单的注释 - 所有方法文件如果导出的是多个方法,不允许在定义方法时导出,必须在文件底部一一导出,并附上方法简单的注释
- 方法头部必须有使用注释
``` js ```js
// 正确 // 正确
import {Req, IsPhone} from '@/common/utils'; import {Req, IsPhone} from '@/common/utils';
@ -76,17 +35,7 @@ import {Req} from '@/common/utils/request';
import {IsPhone} from '@/common/utils/utils'; import {IsPhone} from '@/common/utils/utils';
// 正确 // 正确
/**
* 判断是否为手机号
* @param {String | Number} str 手机号
* @return {Boolean}
*/
const IsPhone = (str) => {....} const IsPhone = (str) => {....}
/**
* 判断是否为邮箱
* @param {String} str 邮箱号
* @return {Boolean}
*/
const IsEmail = (str) => {....} const IsEmail = (str) => {....}
export { export {
// 判断手机号 // 判断手机号
@ -100,27 +49,20 @@ export const IsPhone = (str) => {....}
export const IsEmail = (str) => {....} export const IsEmail = (str) => {....}
``` ```
### 组件
- 请务必使用easycom模式引入第三方组件
- 所有的自定义组件文件名以大驼峰命名且在templet中使用也用大驼峰形式使用
- 组件分两种类型业务类型、UI功能类型命名区分(Bsxxx:业务组件、Uixxx:UI功能组件)
- 页头写好使用注释props slot methods events
## 组件
### 状态管理以及存储 - 请务必使用 easycom 模式引入第三方组件
- 根目录的 components 只放置真正的组件,某个页面的业务模块应该在 pages 的相应目录下新建 components 目录放置
- 所有的自定义组件文件名以大驼峰命名,且在 templet 中使用也用大驼峰形式使用
- 每个功能模块都要对应一个数据状态管理模块 ## 请求
- 必须通过 mutations 修改 state 中的数据
- 接口调用及后续数据逻辑处理应在 actions 中进行,保证多处调用时行为统一
- 使用本存储时必须与 vuex 结合使用,不允许直接在页面中操作本地存储;
- 所有存储 key 必须在 config 中 sotrageKey.js 中定义;
- 所有请求方法命名以Api+请求类型+具体方) 法命名
- 所有请求使用 ToAsyncAwait 包裹
- 不允许使用 try catch 和 then 处理返回结果
### 请求 ```js
- 所有请求方法命名以Api+请求类型+具体方法) 法命名
- 所有请求使用ToAsyncAwait 包裹
- 不允许使用try catch 和 then 处理返回结果
``` js
// 使用示例 // 使用示例
// xxapi.js // xxapi.js
import {ToAsyncAwait, ReqestTk} from '@/common/utils' import {ToAsyncAwait, ReqestTk} from '@/common/utils'
@ -142,47 +84,8 @@ export const IsEmail = (str) => {....}
} }
``` ```
### 图片
- 按pages目录结果放置图片
- 有公共使用的图片请放到static/common文件夹内
### 样式相关
- 样式命名方式采取BEM命名优先法则
- 参考 src/styles/gobalVariables.module.less颜色、字号、边距、圆角尽可能复用已有的变量
- 没有特殊需求不允许写全局样式stlye 标签必须加 scoped
- 没有特殊需求不允许定义或使用 ID 选择器、属性选择器
## 代码库
### 分支管理
- 分支命名:特性/任务-日期-创建人例如fix/213-0505-ch
- 所有新开发功能或修复BUG应基于 prod 分支创建未上线以提测的Bug则在原有开发分支上继续开发即可
- 提测则将开发分支合并到功能分支,再将功能分支合并到 test 分支,严禁将 test 分支合并进其他任何分支
- 测试通过后先将 beta 分支合并到功能分支解决冲突,再通过提 push request 通知负责人进行代码审查,审查通过后由负责人合并代码
- 预发通过后先将 特性分支 分支合并到 beta 分支解决冲突,再将 beta 分支合并到 dev 分支,此操作只能由负责人进行
- 解决冲突时如涉及其他开发者代码,应跟当事人确认无误后再合并;
### 提交代码
- 提交前确认项目能正常运行,改动部分功能正常
- 严格遵循 eslint、prettier 代码规范
- 严禁使用 git commit --no-verify -m "xxx" 强制提交代码
- 规范提交信息
| 前缀 | 使用场景 | 示例 |
| -------- | ------------------------------ | -------------------------- |
| feat | 新增功能点、模块 | feat: 用户管理 |
| fix | 修复 BUG | fix: 用户管理分页异常 |
| doc | 文档、注释更新 | doc: README |
| style | 样式、不影响逻辑的代码格式更新 | style: 用户管理标题字号 |
| refactor | 重构功能点、模块 | refactor: 路由模块逻辑重构 |
| test | 测试 | test: 测试工具类 |
| revert | 撤回提交 | revert: 有文件漏提交 |
| build | 编译打包 | build: 编译用户管理 |
| merge | 合并分支 | merge: beta into dev |
| perf | 性能、体验、逻辑优化 | pref: 路由模块解析性能 |
| conf | 配置更新 | conf: 项目 base 路径 |
| chore | 其他 | chore: 其他 |
## 图片
- 按 pages 目录结果放置图片
- 有公共使用的图片请放到 static/common 文件夹内

@ -1,14 +0,0 @@
<!--
* @Author: ch
* @Date: 2022-05-30 17:20:49
* @LastEditors: ch
* @LastEditTime: 2022-05-30 17:29:43
* @Description: file content
-->
# uni提供的请求方式使用不方便
# HBuild 打包繁琐
使用unicli改进自动化部署
# 从不同页面进入购物车要展示1级或2级页面样式的购物车
# flex布局对齐方式的兼容问题

@ -1,46 +0,0 @@
/*
* @Author: ch
* @Date: 2022-05-05 14:40:00
* @LastEditors: ch
* @LastEditTime: 2022-05-26 19:04:26
* @Description: 根据git分支生成对应环境的环境变量
* 开发时如果环境变量换了可以不用重启服务直接运行node env.config.js即可
*/
const fs = require('fs');
const path = require('path');
const envConfig = {
dev : {
baseUrl: 'https://k8s-horse-gateway.mashibing.cn',
staticUrl : 'https://k8s-shop-app.mashibing.cn',
imUrl : 'wss://k8s-horse-gateway.mashibing.cn'
},
test : {
baseUrl: 'https://k8s-horse-gateway.mashibing.cn',
staticUrl : 'https://k8s-shop-app.mashibing.cn',
imUrl : 'wss://k8s-horse-gateway.mashibing.cn'
},
beta : {
baseUrl: 'https://you-gateway.mashibing.com',
staticUrl : 'https://you-app.mashibing.com',
imUrl : 'wss://you-gateway.mashibing.com'
},
prod : {
baseUrl: 'https://you-gateway.mashibing.com',
staticUrl : 'https://you-app.mashibing.com',
imUrl : 'wss://you-gateway.mashibing.com'
}
}
let curEnvConfig = null;
const argv = global.process.argv;
for(key in envConfig){
if(argv.includes(`--ENV:${key}`)){
curEnvConfig = envConfig[key];
break;
}
}
if(!curEnvConfig){
curEnvConfig = envConfig.dev;
}
fs.writeFileSync(`${path.resolve(__dirname, './src/common/config')}/env.js`,
`const ENV = ${JSON.stringify(curEnvConfig)}; export default ENV;`);

23183
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,15 +3,18 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "node env.config.js & npm run dev:h5", "server": "npm run dev:h5",
"serve:bate": "node env.config.js --ENV:beta & npm run dev:h5", "server:test": "npm run dev:h5-test",
"serve:prod": "node env.config.js --ENV:prod & npm run dev:h5", "server:bate": "npm run dev:h5-bate",
"build": "npm run build:h5", "server:prod": "npm run dev:h5-prod",
"build:test": "npm run build:h5-test",
"build:bate": "npm run build:h5-bate",
"build:prod": "npm run build:h5-prod",
"build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build", "build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
"build:custom": "cross-env NODE_ENV=production uniapp-cli custom", "build:custom": "cross-env NODE_ENV=production uniapp-cli custom",
"build:h5": "node env.config.js --ENV:test & cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build", "build:h5-test": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode test",
"build:h5:bate": "node env.config.js --ENV:beta & cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build", "build:h5-bate": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode bate",
"build:h5:prod": "node env.config.js --ENV:prod & cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build", "build:h5-prod": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode prod",
"build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build", "build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build", "build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build", "build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
@ -29,6 +32,9 @@
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch", "dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
"dev:custom": "cross-env NODE_ENV=development uniapp-cli custom", "dev:custom": "cross-env NODE_ENV=development uniapp-cli custom",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve", "dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
"dev:h5-test": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode test",
"dev:h5-bate": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode bate",
"dev:h5-prod": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode prod",
"dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch", "dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch",
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch", "dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch", "dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
@ -71,35 +77,36 @@
"@dcloudio/uni-quickapp-webview": "^2.0.1-34720220422002", "@dcloudio/uni-quickapp-webview": "^2.0.1-34720220422002",
"@dcloudio/uni-stat": "^2.0.1-34720220422002", "@dcloudio/uni-stat": "^2.0.1-34720220422002",
"@vue/shared": "^3.0.0", "@vue/shared": "^3.0.0",
"caniuse-lite": "^1.0.30001640",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"flyio": "^0.6.2", "flyio": "^0.6.2",
"regenerator-runtime": "^0.12.1",
"vue": "^2.6.11",
"vuex": "^3.2.0",
"js-util-all": "^1.0.6", "js-util-all": "^1.0.6",
"mp-html": "^2.2.2", "mp-html": "^2.2.2",
"regenerator-runtime": "^0.12.1",
"uni-read-pages": "^1.0.5", "uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.7", "uni-simple-router": "^2.0.7",
"uview-ui": "^2.0.29" "uview-ui": "^2.0.29",
"vue": "^2.6.11",
"vuex": "^3.2.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/runtime": "~7.12.0", "@babel/runtime": "~7.12.0",
"@dcloudio/types": "^2.6.7", "@dcloudio/types": "^2.6.7",
"@dcloudio/uni-automator": "^2.0.1-34720220422002", "@dcloudio/uni-automator": "2.0.2-4010520240507001",
"@dcloudio/uni-cli-i18n": "^2.0.1-34720220422002", "@dcloudio/uni-cli-i18n": "2.0.2-4010520240507001",
"@dcloudio/uni-cli-shared": "^2.0.1-34720220422002", "@dcloudio/uni-cli-shared": "2.0.2-4010520240507001",
"@dcloudio/uni-migration": "^2.0.1-34720220422002", "@dcloudio/uni-migration": "2.0.2-4010520240507001",
"@dcloudio/uni-template-compiler": "^2.0.1-34720220422002", "@dcloudio/uni-template-compiler": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.1-34720220422002", "@dcloudio/vue-cli-plugin-hbuilderx": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-uni": "^2.0.1-34720220422002", "@dcloudio/vue-cli-plugin-uni": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.1-34720220422002", "@dcloudio/vue-cli-plugin-uni-optimize": "2.0.2-4010520240507001",
"@dcloudio/webpack-uni-mp-loader": "^2.0.1-34720220422002", "@dcloudio/webpack-uni-mp-loader": "2.0.2-4010520240507001",
"@dcloudio/webpack-uni-pages-loader": "^2.0.1-34720220422002", "@dcloudio/webpack-uni-pages-loader": "2.0.2-4010520240507001",
"@vue/cli-plugin-babel": "~4.5.15", "@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-service": "~4.5.15", "@vue/cli-service": "~4.5.15",
"babel-plugin-import": "^1.11.0", "babel-plugin-import": "1.13.8",
"cross-env": "^7.0.2", "cross-env": "7.0.3",
"jest": "^25.4.0", "jest": "25.5.4",
"mini-types": "*", "mini-types": "*",
"miniprogram-api-typings": "*", "miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0", "postcss-comment": "^2.0.0",

@ -1,3 +1,10 @@
<!--
* @Author: ch
* @Date: 2022-05-27 17:44:36
* @LastEditors: ch
* @LastEditTime: 2022-06-29 21:37:10
* @Description: file content
-->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
@ -14,7 +21,7 @@
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head> </head>
<body> <body class="page">
<noscript> <noscript>
<strong>Please enable JavaScript to continue.</strong> <strong>Please enable JavaScript to continue.</strong>
</noscript> </noscript>

@ -0,0 +1,18 @@
/*
* @Author: ch
* @Date: 2022-05-31 11:17:38
* @LastEditors: ch
* @LastEditTime: 2022-05-31 11:35:10
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest} from '@/common/utils';
import { AD_PLATFORM } from '../dicts/ad';
const BASE_URL = '/mall/marketing';
// 获取广告列表
export const ApiGetAdList = (params) => ToAsyncAwait(MsbRequest.get(`${BASE_URL}/app/advertisement`, {
platform : AD_PLATFORM.MOBILE,
...params
}))

@ -2,13 +2,34 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-06 17:29:13 * @Date: 2022-04-06 17:29:13
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-04-15 14:17:14 * @LastEditTime: 2022-05-31 11:18:44
* @Description: file content * @Description: file content
*/ */
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils'; import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/base'; const BASE_URL = '/mall/base';
const BASE_URL_UC = '/uc';
/**
* 登录
* @param {*} data
*/
export const ApiPostLogin = (data) => ToAsyncAwait(MsbRequest.post(`${BASE_URL_UC}/user/login`, data));
/**
* 退出登录
* @param {*} data
*/
export const ApiGetLogout= () => ToAsyncAwait(MsbRequest.get(`${BASE_URL_UC}/user/logout`));
/**
* 获取手机验证码
* @param {*} params
*/
export const ApiGetCode = (params) => ToAsyncAwait(MsbRequest.get(`${BASE_URL_UC}/user/login/verificationCode`, params));
/** /**
* 获取收货地址 * 获取收货地址
*/ */

@ -0,0 +1,66 @@
/*
* @Author: ch
* @Date: 2022-06-20 11:38:48
* @LastEditors: ch
* @LastEditTime: 2022-06-30 11:53:57
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/comment';
/**
* 根据商品获取评论列表
* @param {*} param0
*/
export const ApiGetCommentList = (params) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/comment`,params, {
notVerifyToken: true
}));
/**
* 根据商品获取评论总数
* @param {*} param0
*/
export const ApiGetCommentCount = ({productId}) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/comment/getAllCommentCountByProductId/${productId}`,{}, {
notVerifyToken: true
}));
/**
* 根据商品获取标签评论总数
* @param {*} param0
*/
export const ApiGetCommentTabCount = ({productId}) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/comment/listCommentLabel/${productId}`,{}, {
notVerifyToken: true
}));
/**
* 获取订单评论详情
* @param {*} param0
*/
export const ApiGetOrderCommentDetail = ({orderId}) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/comment/listOrderCommentByOrderId/${orderId}`));
/**
* 获取评论详情
* @param {*} param0
*/
export const ApiGetCommentDetail = ({commentId}) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/comment/getCommentDetail/${commentId}`,{}, {
notVerifyToken: true
}));
/**
* 新增评论
* @param {*} param0
*/
export const ApiPostComment = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/app/comment`, data));
/**
* 更新评论有用数
* @param {*} param0
*/
export const ApiPutCommentUseful = (data) =>
ToAsyncAwait(MsbRequestTk.put(`${BASE_URL}/app/comment/updateUsefulCount`,data));

@ -1,48 +1,16 @@
// /* /*
// * @Author: ch * @Author: ch
// * @Date: 2022-05-18 15:21:10 * @Date: 2022-05-27 17:44:36
// * @LastEditors: ch * @LastEditors: ch
// * @LastEditTime: 2022-05-18 17:24:37 * @LastEditTime: 2022-06-09 11:34:36
// * @Description: file content * @Description: file content
// */ */
// import { MsbSkt } from "../utils/webSkt"; import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
// import { CreateUUID } from '@/common/utils'; const BASE_URL = '/mall/im';
// /** /**
// * 系统消息心跳 * 获取soket登录秘钥
// */ */
// export const ApiSktSysHeart = () => MsbSkt.send({ export const ApiGetSoketTicket = () => ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/ticket`, {
// traceId: CreateUUID(), ticketType: 'CONNECT_TICKET'
// traceType: '0', }));
// content: { text: "ping" }
// });
// /**
// * 获取系统通知会话
// * @param {*} content
// */
// export const ApiSktSysGetSession = (content) => MsbSkt.send({
// traceId: CreateUUID(),
// traceType: '1',
// content
// });
// /**
// * 获取系统消息历史消息
// * @param {*} content
// */
// export const ApiSktSysGetHistory = (content) => MsbSkt.send({
// traceId: CreateUUID(),
// traceType: '2',
// content
// });
// /**
// * 系统消息已读
// * @param {*} content
// */
// export const ApiSktSysGetHistory = (content) => MsbSkt.send({
// traceId: CreateUUID(),
// traceType: '6',
// content
// });

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-29 17:38:17 * @Date: 2022-03-29 17:38:17
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-10 16:14:53 * @LastEditTime: 2022-06-23 16:21:32
* @Description: file content * @Description: file content
*/ */
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils'; import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
@ -84,8 +84,11 @@ export const ApiPutCancelOrder = (data) =>
export const ApiGetOrderStatistics = () => export const ApiGetOrderStatistics = () =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/tradeOrder/statistics`)); ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/tradeOrder/statistics`));
/**
* 获取待评价订单详请列表
*/
export const ApiGetCommentOrderDetailList = (params) =>
ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/app/tradeOrder/listOrderProductWaitComment`,params))
/** /**

@ -0,0 +1,51 @@
/*
* @Author: ch
* @Date: 2022-04-28 16:30:54
* @LastEditors: ch
* @LastEditTime: 2022-07-09 10:16:00
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/trade';
export const ApiPostCashierPrepay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/cashierPrepay`, data));
/**
* 微信h5支付获取支付URL
* @param {*} data
*/
export const ApiPostWxH5Pay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/wxPay/h5`, data));
/**
* 微信JSAPI支付获取支付参数
* @param {*} data
*/
export const ApiPostWxJsApiPay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/wxPay/jsapi`, data));
/**
* 微信APP支付
* @param {*} data
*/
export const ApiPostWxAppPay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/wxPay/app`, data));
/**
* 支付宝APP支付
* @param {*} data
*/
export const ApiPostAliAppPay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/aliPay/app`, data));
/**
* 支付宝h5支付获取支付URL
* @param {*} data
*/
export const ApiPostAliH5Pay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/payCenter/aliPay/wap`, data));

@ -2,13 +2,12 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-28 16:30:54 * @Date: 2022-04-28 16:30:54
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-17 20:07:26 * @LastEditTime: 2022-06-29 17:16:50
* @Description: file content * @Description: file content
*/ */
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils'; import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/trade';
// 第三方鉴权服务 // 第三方鉴权服务
const AUTH_URL = '/third'; const AUTH_URL = '/third';
const APPID = 'wxd2015f0c56defa02'; const APPID = 'wxd2015f0c56defa02';
@ -33,24 +32,3 @@ export const ApiGetOpenId = ({code}) =>
*/ */
export const ApiPostThirdInfo = (data) => export const ApiPostThirdInfo = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${AUTH_URL}/third/saveThirdInfo`, {...data, appId:APPID})); ToAsyncAwait(MsbRequestTk.post(`${AUTH_URL}/third/saveThirdInfo`, {...data, appId:APPID}));
/**
* 微信h5支付获取支付URL
* @param {*} data
*/
export const ApiPostWxH5Pay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/pay/wxPay/h5`, data));
/**
* 微信JSAPI支付获取支付参数
* @param {*} data
*/
export const ApiPostWxJsApiPay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/pay/wxPay/jsapi`, data));
/**
* 微信APP支付
* @param {*} data
*/
export const ApiPostWxAppPay = (data) =>
ToAsyncAwait(MsbRequestTk.post(`${BASE_URL}/pay/wxPay/app`, data));

@ -0,0 +1,42 @@
/*
* @Author: ch
* @Date: 2022-05-31 11:05:08
* @LastEditors: ch
* @LastEditTime: 2022-05-31 17:23:02
* @Description: file content
*/
const AD_PLATFORM = {
PC: 2,
MOBILE : 1
}
const AD_LOCATION = {
// 首页轮播图
HOME_BANNER: 1,
// 首页精装区
HOME_HARDCOVER: 2,
// 分类banner
CATEGORY_BANNER : 3
}
const AD_JUMP_TYPE = {
// 商品详情
GOODS: 1,
// 分类
CATEGORY: 2,
// 链接
LINK: 3,
// 不跳转
NO_JUMP : 4
}
export {
// 广告所属平台
AD_PLATFORM,
// 广告位置
AD_LOCATION,
// 广告跳转类型
AD_JUMP_TYPE
}

@ -0,0 +1,33 @@
/*
* @Author: ch
* @Date: 2022-06-20 11:10:23
* @LastEditors: ch
* @LastEditTime: 2022-06-28 16:33:25
* @Description: file content
*/
export default {
TYPE : {
// 评价
COMMENT: 1,
// 追评
FOLLOW_COMMENT: 2,
// 回复
ANSWER: 3,
},
// 是否显示
DISPLAY: {
SHOW: 1,
HIDE : 0
},
// 用户类型
USER_TYPE: {
STORE : 1,
USER : 2
},
// 是否默认评价
IS_DEFAULT_COMMENT: {
YES: 1,
NOT : 0
},
RATE_LABEL : ['非常不满意','不满意','一般','满意','非常满意']
}

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-26 11:49:16 * @Date: 2022-05-26 11:49:16
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-26 17:00:06 * @LastEditTime: 2022-06-22 11:23:02
* @Description: file content * @Description: file content
*/ */
@ -11,7 +11,8 @@ export const ORDER_STATUS = {
// 待支付 // 待支付
AWAIT_PAY: 1 AWAIT_PAY: 1
} }
export const ORDER_TYPE = { export default {
TYPE : {
//(1, "普通订单"), //(1, "普通订单"),
NORMAL: 1, NORMAL: 1,
//(2, "免费订单"), //(2, "免费订单"),
@ -20,4 +21,15 @@ export const ORDER_TYPE = {
SECKILL: 3, SECKILL: 3,
//(4, "虚拟商品订单"), //(4, "虚拟商品订单"),
VIRTUAL : 4 VIRTUAL : 4
},
// 订单状态 1待支付2已关闭3已支付4已发货5已收货6已完成7已追评
STATUS: {
AWAIT_PAY: 1,
CLOSE: 2,
FINISH_PAY: 3,
FINISH_SEND_GOODS: 4,
FINISH_TAKE_GOODS: 5,
FINISH: 6,
FINISH_FOLLOW_COMMENT : 7
}
} }

@ -2,83 +2,130 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-18 14:54:47 * @Date: 2022-05-18 14:54:47
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 22:51:47 * @LastEditTime: 2022-06-14 17:24:14
* @Description: file content * @Description: file content
*/ */
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils"; import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
const connect = Symbol('connect'), import './potoReq';
send = Symbol('send'), import './protoRsp'
onResponse = Symbol('onResponse'), const connect = Symbol('connect');
onMessage = Symbol('onMessage'), const send = Symbol('send');
updateData = Symbol('updateData') const onMessage = Symbol('onMessage');
; const fromatPotoReq = (traceId, traceType, content) => {
export default class MsbIm { let messageModel = new proto.ReqModel();
option = { messageModel.setTraceid(traceId);
ioKey : 'traceId', messageModel.setTracetype(traceType);
content && messageModel.setContent(JSON.stringify(content));
return messageModel.serializeBinary();
},
fromatPotoRsp = (data) => {
const res = proto.RspModel.deserializeBinary(new Uint8Array(data));
let ctx = res.getContent();
ctx = ctx ? JSON.parse(ctx) : {};
if (ctx.payload) {
ctx.payload = JSON.parse(ctx.payload);
}
return {
content: ctx,
traceId: res.getTraceid(),
traceType: res.getTracetype(),
code: res.getCode(),
message: res.getMessage(),
};
};
class MsbIm {
defaultOption = {
ioKey: 'traceId',
reconnect: true, reconnect: true,
logout : false };
}
socket = null; socket = null;
isOpen = false;
queue = {}; queue = {};
interceptors = { interceptors = {
dataChangeBefore: null, dataChangeBefore: null,
dataChangeAfter: null, dataChangeAfter: null,
onLogout : null, onClose: null,
onMessage: null onMessage: null,
}; };
sessionData = []; sessionData = [];
curSessionId = null; curSessionId = null;
constructor(option) { constructor(option) {
this.option = { this.option = {
...this.option, ...this.defaultOption,
...option ...option,
} };
} }
/** /**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功 * 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option * @param {*} option
*/ */
[connect](option) { [connect](option) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.socket = uni.connectSocket({ const open = () => {
...option, console.log('[im] open');
fail(e){ this.isOpen = true;
reject(e); resolve(this.socket);
} };
}); const message = async (res) => {
this.socket.onOpen(() => { const result = fromatPotoRsp(res.data);
this.socket.onMessage(async (res) => {
const result = JSON.parse(res.data);
if (result.content?.payload) {
result.content.payload = JSON.parse(result.content.payload);
}
// 401主动退出
if (result.code === 401) {
this.logout();
return false;
}
this.interceptors.onMessage && this.interceptors.onMessage(result); this.interceptors.onMessage && this.interceptors.onMessage(result);
// 处理服务端主动推送的消息 // 处理服务端主动推送的消息
this[onMessage](result); this[onMessage](result);
// 如果再消息堆里有此消息回调,则执行回调,并删除 // 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]]; const cbk = this.queue[result[this.option.ioKey]];
if (cbk) { if (cbk) {
cbk(result.code !== 200 ? {error:result} : {result:result}); cbk(result.code !== 200 ? { error: result } : { result: result });
delete this.queue[result[this.option.ioKey]]; delete this.queue[result[this.option.ioKey]];
} }
}) };
resolve(this.socket); const close = () => {
console.log('[im] close');
this.interceptors.onClose && this.interceptors.onClose();
};
let isUni = false;
try {
isUni = uni;
} catch (e) {
isUni = false;
}
if (isUni) {
this.socket = uni.connectSocket({
...this.option,
fail(e) {
reject(e);
},
});
this.socket.onOpen(() => {
open();
this.socket.onMessage((res) => {
message(res);
});
}); });
this.socket.onClose(() => { this.socket.onClose(() => {
if (this.option.reconnect && !this.option.logout) { close();
this[connect]();
}
this.option.logout = false;
}); });
} else if (WebSocket) {
try {
this.socket = new WebSocket(this.option.url);
this.socket.binaryType = 'arraybuffer';
this.socket.onopen = () => {
open();
};
this.socket.onmessage = (res) => {
message(res);
};
this.socket.onclose = () => {
close();
};
} catch (e) {
reject(e);
}
}
}); });
} }
/** /**
@ -87,20 +134,36 @@ export default class MsbIm {
*/ */
[send](data) { [send](data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.queue[data[this.option.ioKey]] = ({result, error}) => { if (!this.isOpen) {
return reject('连接未打开');
}
this.queue[data[this.option.ioKey]] = ({ result, error }) => {
if (result) { if (result) {
resolve(result); resolve(result);
} else { } else {
reject(error); reject(error);
} }
}; };
const par = fromatPotoReq(data.traceId, data.traceType, data.content);
let isUni = false;
try {
isUni = uni;
} catch (e) {
isUni = false;
}
if (isUni) {
this.socket.send({ this.socket.send({
data : JSON.stringify(data), data: par,
fail(e) { fail(e) {
reject({error : e}); reject({ error: e });
},
});
} else if (WebSocket) {
this.socket.send(par);
} }
}); });
})
} }
/** /**
* 服务端推送消息只处理服务端主动推送的消息 * 服务端推送消息只处理服务端主动推送的消息
@ -111,67 +174,81 @@ export default class MsbIm {
if (data[this.option.ioKey] || data.code !== 200) { if (data[this.option.ioKey] || data.code !== 200) {
return false; return false;
} }
console.log('[im] 主动接收的消息', data);
let ctx = data.content; let ctx = data.content;
let historyData = [...this.sessionData], let historyData = [...this.sessionData],
newData = []; newData = [];
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId); const hisIndex = historyData.findIndex((i) => i.id === ctx.sessionId);
if(hisIndex >= 0){ if (hisIndex >= 0) {
// 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息 // 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息
const curHisData = historyData[hisIndex]; const curHisData = historyData[hisIndex];
curHisData.messageList.push(ctx); curHisData.messageList.push(ctx);
curHisData.lastMessage = ctx; curHisData.lastMessage = ctx;
// 不在当前会话窗口则向会话消息加1条未读 // 不在当前会话窗口则向会话消息加1条未读
if(ctx.sessionId !== this.curSessionId){ if (ctx.sessionId !== this.curSessionId) {
curHisData.unreadCount++; curHisData.unreadCount++;
} else {
this.setRead({
content: {
sessionId: this.curSessionId,
},
});
} }
newData = historyData; newData = historyData;
}else{ } else {
// 会话列表不存在,则创建一个会话 // 会话列表不存在,则创建一个会话
newData = [...historyData, { newData = [
fromAvatar : ctx.fromAvatar, ...historyData,
fromId : ctx.fromId, {
fromNickname : ctx.fromNickname, fromAvatar: ctx.session.fromAvatar,
id : ctx.id, fromId: ctx.session.fromId,
lastMessage : ctx, fromNickname: ctx.session.fromNickname,
messageList : [ctx], id: ctx.sessionId,
unreadCount : 1 lastMessage: ctx,
}] messageList: [ctx],
} updateTimeStamp: ctx.createTimeStamp,
this.setSessionData(newData) unreadCount: 1,
},
];
} }
init (config) { this.setSessionData(newData);
}
init(config) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const heart = () => { const heart = () => {
// 要优化 心跳没回复需要重连
setTimeout(async () => { setTimeout(async () => {
if (this.isOpen) {
await this[send]({ await this[send]({
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: '0', traceType: 0,
content: { text: "ping" } content: { text: 'ping' },
}).catch((e)=>{}); });
heart();
},5000)
} }
this[connect]({ heart();
}, 1000);
};
this.option = {
...this.option,
...config, ...config,
}).then(() => { };
this[connect]()
.then((res) => {
resolve(res);
heart(); heart();
resolve(this);
}).catch((e)=>{});
}) })
.catch((e) => {
} console.log('eeeee', e);
logout() { });
this.option.logout = true; });
this.socket.close();
this.interceptors.onLogout && this.interceptors.onLogout();
} }
/** /**
* 设置数据 * 设置数据
*/ */
setSessionData(data) { setSessionData(data) {
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData); let newData = JSON.parse(JSON.stringify(data));
this.sessionData = data; this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData); this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
} }
/** /**
@ -187,71 +264,93 @@ export default class MsbIm {
* @param {*} params * @param {*} params
*/ */
async getSessionList(params) { async getSessionList(params) {
const par = {
let {error, result} = await ToAsyncAwait(this[send]({
traceId: CreateUUID(), traceId: CreateUUID(),
traceType : 1, traceType: 1,
...params ...params,
})); };
console.log('[im] 获取会话列表--start', par);
let { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 获取会话列表--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
content.sessionVOS.forEach(item => { // let newData = [];
content.sessionVOS.forEach((item) => {
if (item.lastMessage) { if (item.lastMessage) {
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {}); item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
} }
let historyData = this.sessionData; let historyData = this.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id); let hisIndex = historyData.findIndex((i) => i.id === item.id);
if(hisIndex >= 0){ if (hisIndex < 0) {
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
this.setSessionData(historyData)
}else{
item.messageList = []; item.messageList = [];
const newData = [...historyData, item]
this.setSessionData(newData);
} }
// let historyData = this.sessionData;
// let hisIndex = historyData.findIndex((i) => i.id === item.id);
// if (hisIndex >= 0) {
// historyData[hisIndex].lastMessage = item.lastMessage;
// historyData[hisIndex].unreadCount++;
// newData.push(historyData[hisIndex]);
// } else {
// item.messageList = [];
// newData = [...newData, item];
// }
}); });
this.setSessionData(content.sessionVOS);
return Promise.resolve(result); return Promise.resolve(result);
} }
/** /**
* 获取会话的历史消息记录 * 获取会话的历史消息记录
* @param {*} params * @param {*} params
*/ */
async getHistoryMsg(params) { async getHistoryMsg() {
const {error, result} = await ToAsyncAwait(this[send]({ const curSessionIdx = this.sessionData.findIndex((i) => i.id === this.curSessionId);
const curSession = this.sessionData[curSessionIdx];
console.log(curSession, this.curSessionId, 'this.curSessionId');
const msgList = curSession.messageList || [];
const par = {
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 23, traceType: 2,
...params content: {
})); sessionId: this.curSessionId,
topMessageId: msgList.length ? msgList[0].id : null,
},
};
console.log('[im] 获取会话历史消息--start', par);
const { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 获取会话历史消息--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
if (content.length) { if (content.length) {
let newData = this.sessionData; let newData = this.sessionData;
const hisIdx = newData.findIndex(i => i.id === content[0].sessionId); content.forEach((item) => {
content.forEach(item => { item.payload = JSON.parse(item.payload);
item.payload = JSON.parse(item.payload) });
}) newData[curSessionIdx].messageList = content.concat(newData[curSessionIdx].messageList);
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content);
this.setSessionData(newData); this.setSessionData(newData);
} }
return Promise.resolve(result); return Promise.resolve(result);
} }
/** /**
* 会话已读 * 会话已读
* @param {*} params * @param {*} params
*/ */
async setRead (params){ async setRead(params) {
await this[send]({ const par = {
traceId : CreateUUID(), traceId: CreateUUID(),
traceType : "6", traceType: '6',
...params ...params,
}); };
let newData = this.sessionData.map(item => { console.log('[im] 会话已读--start', par);
const { error, result } = await this[send](par);
console.log('[im] 会话已读--end', result, error);
let newData = this.sessionData.map((item) => {
if (item.id == params.content.sessionId) { if (item.id == params.content.sessionId) {
item.unreadCount = 0; item.unreadCount = 0;
} }
@ -265,28 +364,36 @@ export default class MsbIm {
* @param {*} params * @param {*} params
*/ */
async sendMsg(params) { async sendMsg(params) {
const index = this.sessionData.findIndex(i => i.id === this.curSessionId) const index = this.sessionData.findIndex((i) => i.id === this.curSessionId);
let curSession = this.sessionData[index]; let curSession = this.sessionData[index];
// 临时消息体 // 临时消息体
let par = { let par = {
...params, ...params,
traceId: CreateUUID(), traceId: CreateUUID(),
traceType: 20, traceType: 3,
} };
let msgCtx = { let msgCtx = {
...params.content, ...params.content,
...par, ...par,
fromId: params.fromId, createTimeStamp: new Date().getTime(),
createTimeStamp : (new Date()).getTime(), sendStatus: 'loading',
sendStatus : 'loading' };
if (typeof msgCtx.payload === 'string') {
msgCtx.payload = JSON.parse(msgCtx.payload);
} }
// 点发送,立即把消息加入消息列表,标记为发送中状态 // 点发送,立即把消息加入消息列表,标记为发送中状态
curSession.lastMessage = msgCtx;
curSession.messageList.push(msgCtx); curSession.messageList.push(msgCtx);
this.setSessionData(this.sessionData);
// 超过时间未返回视为发送失败 // 超过时间未返回视为发送失败
this.timerStatus(msgCtx); this.timerStatus(msgCtx);
console.log('[im] 发送消息--start', par);
const { error, result } = await ToAsyncAwait(this[send](par)); const { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 发送消息--end', result, error);
// 接到通知,标记消息是否发送成功 // 接到通知,标记消息是否发送成功
for (let i = curSession.messageList.length; i--;) { for (let i = curSession.messageList.length; i--; ) {
const item = curSession.messageList[i]; const item = curSession.messageList[i];
if (item[this.option.ioKey] === par[this.option.ioKey]) { if (item[this.option.ioKey] === par[this.option.ioKey]) {
curSession.messageList[i].sendStatus = msgCtx.sendStatus = error ? 'fail' : 'success'; curSession.messageList[i].sendStatus = msgCtx.sendStatus = error ? 'fail' : 'success';
@ -294,6 +401,7 @@ export default class MsbIm {
} }
} }
let newData = [...this.sessionData]; let newData = [...this.sessionData];
curSession.lastMessage = msgCtx;
newData[index] = curSession; newData[index] = curSession;
this.setSessionData(newData); this.setSessionData(newData);
if (error) { if (error) {
@ -308,12 +416,17 @@ export default class MsbIm {
*/ */
async resend(params) { async resend(params) {
params.sendStatus = 'loading'; params.sendStatus = 'loading';
this.timerStatus(params) this.timerStatus(params);
const { error, result } = await ToAsyncAwait(this[send]({
console.log('[im] 重新发送消息--start', params);
const { error, result } = await ToAsyncAwait(
this[send]({
traceId: params.traceId, traceId: params.traceId,
traceType: params.traceType, traceType: params.traceType,
content : params.content content: params.content,
})); })
);
console.log('[im] 重新发送消息--end', result, error);
params.createTimeStamp = result.createTimeStamp; params.createTimeStamp = result.createTimeStamp;
if (error) { if (error) {
params.sendStatus = 'fail'; params.sendStatus = 'fail';
@ -323,7 +436,6 @@ export default class MsbIm {
return Promise.resolve(result); return Promise.resolve(result);
} }
timerStatus(msg) { timerStatus(msg) {
setTimeout(() => { setTimeout(() => {
if (msg.sendStatus === 'loading') { if (msg.sendStatus === 'loading') {
msg.sendStatus = 'fail'; msg.sendStatus = 'fail';
@ -335,29 +447,37 @@ export default class MsbIm {
* 主动创建会话 * 主动创建会话
* @param {*} params * @param {*} params
*/ */
async createSession (params){ async createSession(params) {
const { result, error } = await ToAsyncAwait(this[send]({ const par = {
traceId : CreateUUID(), traceId: CreateUUID(),
traceType : 21, traceType: 9,
...params ...params,
})); };
console.log('[im] 主动创建会话--start', par);
const { result, error } = await ToAsyncAwait(this[send](par));
console.log('[im] 主动创建会话--end', result, error);
if (error) { if (error) {
return Promise.reject(error); return Promise.reject(error);
} }
const { content } = result; const { content } = result;
let historyData = this.sessionData; let historyData = this.sessionData;
let curSession = historyData.find(i => i.id === content.id); let curSession = historyData.find((i) => i.id === content.id);
if (!curSession) { if (!curSession) {
curSession = { curSession = {
...content, ...content,
unreadCount: 0, unreadCount: 0,
messageList : [] messageList: [],
} };
const newData = [...historyData, curSession]; const newData = [...historyData, curSession];
this.setSessionData(newData); this.setSessionData(newData);
} }
return Promise.resolve(result); return Promise.resolve(result);
} }
close() {
this.socket.close();
this.socket = null;
this.isOpen = false;
this.setSessionData([]);
}
} }
export default MsbIm;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-18 11:11:05 * @Date: 2022-03-18 11:11:05
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-03-18 11:11:05 * @LastEditTime: 2022-07-12 18:31:15
* @Description: file content * @Description: file content
*/ */
import {RouterMount,createRouter} from 'uni-simple-router'; import {RouterMount,createRouter} from 'uni-simple-router';
@ -13,6 +13,11 @@ const router = createRouter({
}); });
//全局路由前置守卫 //全局路由前置守卫
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
// 兼容页面刷新body样式丢失问题
// console.log(document);
if (document) {
document.body.setAttribute('class', `uni-body ${to.path.replace('/', '').replace(/\//g, '-')}`)
}
next(); next();
}); });
// 全局路由后置守卫 // 全局路由后置守卫

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 18:28:52 * @Date: 2022-03-22 18:28:52
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-21 11:38:51 * @LastEditTime: 2022-06-22 15:31:09
* @Description: file content * @Description: file content
*/ */
import Vue from 'vue' import Vue from 'vue'
@ -17,16 +17,22 @@ const
// 地址列表 // 地址列表
ADDRESS = 'ads', ADDRESS = 'ads',
// oppenId // oppenId
OPPED_ID = 'oi'; OPPED_ID = 'oi',
// 每个浏览器创建一个UUID作为同一个用户的标识
UUID = 'uid',
// 评价图片预览数据
COMMENT_PREVIEW = 'comment_preview';
export default new Vuex.Store({ export default new Vuex.Store({
state : { state: {
token : uni.getStorageSync(TOKEN) || '', token: uni.getStorageSync(TOKEN) || '',
userInfo : JSON.parse(uni.getStorageSync(USER_INFO) || '{}'), userInfo: JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address : JSON.parse(uni.getStorageSync(ADDRESS) || '[]'), address: JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
openId: uni.getStorageSync(OPPED_ID) || '',
uuid: uni.getStorageSync(UUID) || '',
comment_preview: JSON.parse(uni.getStorageSync(COMMENT_PREVIEW) || '{}'),
imData : [], imData : [],
imMsgCount : 0, imMsgCount : 0
openId : uni.getStorageSync(OPPED_ID) || ''
}, },
mutations:{ mutations:{
SET_TOKEN (state, token = ''){ SET_TOKEN (state, token = ''){
@ -41,15 +47,23 @@ export default new Vuex.Store({
state.address = address; state.address = address;
uni.setStorageSync(ADDRESS, JSON.stringify(address)); uni.setStorageSync(ADDRESS, JSON.stringify(address));
}, },
SET_UUID (state, uid){
state.uuid = uid;
uni.setStorageSync(UUID, uid);
},
SET_OPEN_ID (state, data){
state.openId = data;
uni.setStorageSync(OPPED_ID, data);
},
SET_COMMENT_PREVIEW(state, data) {
state.comment_preview = data;
uni.setStorageSync(COMMENT_PREVIEW, JSON.stringify(data));
},
SET_IM_DATA (state, data){ SET_IM_DATA (state, data){
state.imData = data ; state.imData = data ;
}, },
SET_IM_MSG_COUNT (state, data){ SET_IM_MSG_COUNT (state, data){
state.imMsgCount = data; state.imMsgCount = data;
},
SET_OPEN_ID (state, data){
state.openId = data;
uni.setStorageSync(OPPED_ID, data);
} }
}, },
actions : { actions : {

@ -0,0 +1,50 @@
/*
* @Author: ch
* @Date: 2022-04-29 14:26:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:37:21
* @Description: file content
*/
import { ApiPostAliH5Pay, ApiPostAliAppPay } from '@/common/api/pay';
const ENV = process.env;
export const Alipay = async ({orderId})=>{
// #ifdef APP-PLUS
const {error, result} = await ApiPostAliAppPay({orderId});
if(error){
uni.$u.toast(error.message);
return false;
}
const par = result.payDataInfo;
uni.requestPayment({
provider: 'alipay',
orderInfo :par.payData,
success(res) {
uni.navigateTo({
url : `/payResult?orderId=${orderId}&payType=appWx`
});
},
fail(e) {
uni.navigateTo({
url : `/payResult?orderId=${orderId}&payType=appWx`
});
}
}).then(res => {
console.log('res',res);
})
// #endif
// #ifdef H5
const { error, result } = await ApiPostAliH5Pay({
orderId,
returnUrl : decodeURIComponent(`${ENV.VUE_APP_STATIC_URL}/payResult?orderId=${orderId}&payType=alih5`)
});
if(error){
uni.$u.toast(error.message);
return false;
}
window.location.href = result.payDataInfo.payUrl;
// #endif
}

@ -2,27 +2,36 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-20 11:00:07 * @Date: 2022-05-20 11:00:07
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-23 14:54:50 * @LastEditTime: 2022-07-13 10:37:52
* @Description: file content * @Description: file content
*/ */
import MsbIm from '@/common/plugins/msbIm' ; import MsbIm from '@/common/plugins/msbIm' ;
import { ToAsyncAwait } from '@/common/utils'; import { ToAsyncAwait, FormatJsonSearch } from '@/common/utils';
import { ApiGetCurrentUser } from '@/common/api/account'; import { ApiGetCurrentUser } from '@/common/api/account';
import { ApiGetSoketTicket } from '@/common/api/im';
import $store from '@/common/store'; import $store from '@/common/store';
import ENV from '@/common/config/env'; const ENV = process.env;
const Im = new MsbIm({ const Im = new MsbIm({
reconnect: true, reconnect: true,
}); });
const ImInit = async () => { const ImInit = async () => {
const { error } = await ApiGetCurrentUser(); const { error, result } = await ApiGetSoketTicket();
if (error) { if (error) {
return false; return false;
} }
const par = FormatJsonSearch({
client: result.client,
ticket: result.ticket,
// 1普通用户 2客服链接
connect: 1,
user: $store.state.userInfo.id,
nickname: $store.state.userInfo.nickname,
avatar : $store.state.userInfo.avatar
})
await ToAsyncAwait(Im.init({ await ToAsyncAwait(Im.init({
// url: `wss://k8s-horse-gateway.mashibing.cn/ws?client=${$store.state.token}&type=1` url: `${ENV.VUE_APP_IM_URL}/ws${par}`
url: `${ENV.imUrl}/ws?client=${$store.state.token}&type=1`
})) }))
}; };
@ -32,11 +41,10 @@ Im.interceptors.dataChangeAfter = () => {
Im.sessionData.forEach(i => { Im.sessionData.forEach(i => {
msgCount += i.unreadCount; msgCount += i.unreadCount;
}) })
console.log(Im.sessionData)
$store.commit('SET_IM_MSG_COUNT', msgCount); $store.commit('SET_IM_MSG_COUNT', msgCount);
} }
Im.interceptors.onLogout = () => { Im.interceptors.onClose = () => {
Im.setSessionData([]); Im.setSessionData([]);
Im.setCurSessionId(null); Im.setCurSessionId(null);
$store.commit('SET_IM_DATA', []); $store.commit('SET_IM_DATA', []);

@ -2,17 +2,22 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 16:52:28 * @Date: 2022-03-22 16:52:28
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-20 11:42:33 * @LastEditTime: 2022-06-29 17:28:39
* @LastEditTime: 2022-06-29 17:22:32
* @Description: 所有工具类统一在这输出 * @Description: 所有工具类统一在这输出
*/ */
import * as util from './utils'; import * as util from './utils';
import * as requset from './requset'; import * as requset from './requset';
import * as im from './im'; import * as im from './im';
import * as wxpay from './wxpay'; import * as wxpay from './wxpay';
import * as uploadFileOss from './uploadFileOss';
import * as alipay from './alipay';
export * from './utils'; export * from './utils';
export * from './requset'; export * from './requset';
export * from './im'; export * from './im';
export * from './wxpay'; export * from './wxpay';
export * from './uploadFileOss';
export * from './alipay';
export default { ...util, ...requset, ...im, ...wxpay} export default { ...util, ...requset, ...im, ...wxpay, ...uploadFileOss, ...alipay}

@ -2,57 +2,12 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-06 15:33:55 * @Date: 2022-05-06 15:33:55
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-26 19:04:50 * @LastEditTime: 2022-07-13 10:38:34
* @Description: file content * @Description: file content
*/ */
import { ApiPostWxH5Pay, ApiPostWxJsApiPay } from '@/common/api/wx';
import ENV from '@/common/config/env';
import { Wxpay } from './wxpay'; import { Wxpay } from './wxpay';
export const pay = ({orderId, openId, payType})=>{ export const pay = ({orderId, openId, payType})=>{
if(payType === 'wxpay'){ if(payType === 'wxpay'){
Wxpay({orderId, openId}); Wxpay({orderId, openId});
} }
// #ifdef H5
if(openId) {
// 微信JSAPI
const {error, result} = await ApiPostWxJsApiPay({orderId,openId});
if(error){
uni.$u.toast(error.message);
return false;
}
/*
* 公众号id appId String(16) wx8888888888888888
时间戳 timeStamp String(32) 1414561699 当前的时间
随机字符串 nonceStr String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串不长于32位推荐随机数生成算法
订单详情扩展字符串 package String(128) prepay_id=123456789 统一下单接口返回的prepay_id参数值提交格式如prepay_id=***
签名方式 signType String(32) MD5 签名类型默认为MD5支持HMAC-SHA256和MD5注意此处需与统一下单的签名类型一致
签名 paySign String(64) C380BEC2BFD727A4B6845133519F3AD6 签名
*/
const par = result.dataInfo;
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId : par.appId,
timeStamp : par.timeStamp,
nonceStr : par.nonceStr,
package : par.packageValue,
signType : par.signType,
paySign : par.paySign
}, res => {
if(res.err_msg !== 'get_brand_wcpay_request:cancel'){
uni.navigateTo({
url : `/payResult?orderId=${orderId}&payType=wxjsapi`
});
}
})
}else{
// h5支付
const {error, result} = await ApiPostWxH5Pay({orderId});
if(error){
uni.$u.toast(error.message);
return false;
}
const redirect_url = decodeURIComponent(`${ENV.staticUrl}/payResult?orderId=${orderId}&payType=wxh5`);
window.location.href = `${result.dataInfo.payUrl}&redirect_url=${redirect_url}`;
}
// #ednif
} }

@ -2,14 +2,21 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-17 17:42:32 * @Date: 2022-03-17 17:42:32
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-23 15:19:36 * @LastEditTime: 2022-07-13 10:39:07
* @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法 * @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法
*/ */
import MsbUniRequest from '@/common/plugins/msbUniRequest'; import MsbUniRequest from '@/common/plugins/msbUniRequest';
import $store from '@/common/store'; import $store from '@/common/store';
import ENV from '@/common/config/env'; import { CreateUUID } from '@/common/utils';
const ENV = process.env;
// 获取已有的UUID没则创建一个并保存到locaStorage中下次使用
let uuid = $store.state.uuid
if (!uuid) {
uuid = CreateUUID(16, 2);
$store.commit('SET_UUID', uuid);
}
/** /**
* 接口返回成功结果统一处理 * 接口返回成功结果统一处理
* @param {*} response * @param {*} response
@ -75,7 +82,7 @@ const clearRepeat = (option) =>{
// 不需要token的接口封装 // 不需要token的接口封装
const MsbRequest = new MsbUniRequest(); const MsbRequest = new MsbUniRequest();
MsbRequest.baseUrl = ENV.baseUrl; MsbRequest.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequest.use('request', (option) => { MsbRequest.use('request', (option) => {
if(option.header.repeat){ if(option.header.repeat){
@ -85,6 +92,7 @@ MsbRequest.use('request', (option) => {
return isRepeatVerify; return isRepeatVerify;
} }
} }
option.header.uid = uuid;
return option; return option;
}) })
MsbRequest.use('success', successIntercept); MsbRequest.use('success', successIntercept);
@ -94,17 +102,19 @@ MsbRequest.use('error', errorIntercept);
// 需要token的接口封装 // 需要token的接口封装
const MsbRequestTk = new MsbUniRequest(); const MsbRequestTk = new MsbUniRequest();
MsbRequestTk.baseUrl = ENV.baseUrl; MsbRequestTk.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequestTk.use('request', (option) => { MsbRequestTk.use('request', (option) => {
const token = $store.state.token; const token = $store.state.token;
if(!token){ option.header.uid = uuid;
if(!token && !option.header.notVerifyToken){
// 登录状态处理没有token直接跳转至登录 // 登录状态处理没有token直接跳转至登录
uni.redirectTo({ uni.redirectTo({
url: '/login' url: '/login'
}); });
return Promise.reject({message:'要先登录才能操作哦~'}); return Promise.reject({message:'要先登录才能操作哦~'});
}else{ }
delete option.header.notVerifyToken
option.header = {...option.header, Authorization:token}; option.header = {...option.header, Authorization:token};
if(option.header.repeat){ if(option.header.repeat){
@ -115,7 +125,6 @@ MsbRequestTk.use('request', (option) => {
} }
} }
return option; return option;
}
}) })
MsbRequestTk.use('success', successIntercept); MsbRequestTk.use('success', successIntercept);
MsbRequestTk.use('error', errorIntercept); MsbRequestTk.use('error', errorIntercept);

@ -0,0 +1,46 @@
/*
* @Author: ch
* @Date: 2022-06-21 15:03:11
* @LastEditors: ch
* @LastEditTime: 2022-06-22 14:49:20
* @Description: file content
*/
import { ApiPostGetOssConfig } from '@/common/api/oss';
import {ToAsyncAwait} from '@/common/utils'
/**
*
* @param {*} file 文件
* @param {*} param1 获取OSS鉴权信息参数参考ApiPostGetOssConfig接口
* @returns {Promise}
*/
export const uploadFileOss = (file, {configId, serviceName}) =>{
return ToAsyncAwait(new Promise(async (resolve, reject) => {
const urlArr = file.url.split('/');
const fileName = file.name || urlArr[urlArr.length - 1];
const { error, result:oss } = await ApiPostGetOssConfig({ configId : `${configId}/`, serviceName });
if (error) {
reject(error);
return false
}
uni.uploadFile({
name : 'file',
filePath : file.url,
url : oss.host,
formData : {
name : fileName,
key : `${oss.dir}${'${filename}'}`,
policy : oss.policy,
OSSAccessKeyId : oss.accessId,
success_action_status : 200,
signature : oss.signature
},
success : async (res)=>{
resolve(`${oss.host}/${oss.dir}${fileName}`);
},
fail(e) {
reject(e);
}
})
}
))
}

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-17 19:15:10 * @Date: 2022-03-17 19:15:10
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-23 11:40:29 * @LastEditTime: 2022-07-13 10:39:35
* @Description: 一些无法归类的公共方法容器 * @Description: 一些无法归类的公共方法容器
*/ */
@ -11,9 +11,11 @@ import {
isPhone as IsPhone, isPhone as IsPhone,
formatDate as FormatDate, formatDate as FormatDate,
creatUuid as CreateUUID, creatUuid as CreateUUID,
formatSearchJson as FormatSearchJson formatSearchJson as FormatSearchJson,
formatJsonSearch as FormatJsonSearch
} from "js-util-all"; } from "js-util-all";
import {AD_JUMP_TYPE} from '@/common/dicts/ad';
/** /**
* 首次运行时把定时器赋值给一个变量 第二次执行时 * 首次运行时把定时器赋值给一个变量 第二次执行时
@ -23,17 +25,61 @@ import {
*/ */
const Debounce = (fn, delay) => { const Debounce = (fn, delay) => {
let timer let timer
return function() { return function () {
const that = this const that = this
const _args = arguments // 存一下传入的参数 const _args = arguments // 存一下传入的参数
if (timer) { if (timer) {
clearTimeout(timer) clearTimeout(timer)
} }
timer = setTimeout(function() { timer = setTimeout(function () {
fn.apply(that, _args) fn.apply(that, _args)
}, delay) }, delay)
} }
} }
/**
* 广告跳转
* 兼容APP根据域名判断站内跳转还是站外跳转
* @param {*} link
*/
const AdJump = (item) => {
switch (item.jumpType) {
case AD_JUMP_TYPE.GOODS:
uni.navigateTo({
url: `/goodsDetail?id=${item.jumpUrl}`
});
break;
case AD_JUMP_TYPE.CATEGORY:
uni.navigateTo({
url: `/goodsList?categoryId=${item.jumpUrl}`
});
break;
case AD_JUMP_TYPE.LINK:
// #ifdef H5
window.location.href = item.jumpUrl;
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(item.jumpUrl);
// #endif
break;
default:
break
}
}
/**
* api接口错误处理
* @param {*} error 错误体
* @param {*} name 接口名 非必传如操作时错误提示不需要提示接口名时可不传
* @return Boolean true 存在错误并处理 false无错误
*/
const HandleApiError = (error, name) => {
let result = false
if (error) {
const tip = name ? `${name}错误:` : ``;
uni.$u.toast(`${tip}${error.message}`);
result = true;
}
return result;
}
// 工具类的文件需要把文件提供的工具类统一放最下方做一个统一输出 // 工具类的文件需要把文件提供的工具类统一放最下方做一个统一输出
export { export {
// async await 标识结果处理 // async await 标识结果处理
@ -43,7 +89,11 @@ export {
// 时间格式化 // 时间格式化
FormatDate, FormatDate,
FormatSearchJson, FormatSearchJson,
FormatJsonSearch,
CreateUUID, CreateUUID,
// 防抖函数 // 防抖函数
Debounce Debounce,
// 广告跳转
AdJump,
HandleApiError
} }

@ -2,12 +2,12 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-29 14:26:10 * @Date: 2022-04-29 14:26:10
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-26 20:28:48 * @LastEditTime: 2022-07-13 10:40:10
* @Description: file content * @Description: file content
*/ */
import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/wx'; import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/pay';
import ENV from '@/common/config/env'; const ENV = process.env;
export const Wxpay = async ({orderId,openId})=>{ export const Wxpay = async ({orderId,openId})=>{
// #ifdef APP-PLUS // #ifdef APP-PLUS
@ -16,7 +16,7 @@ export const Wxpay = async ({orderId,openId})=>{
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
const par = result.dataInfo; const par = result.payDataInfo;
uni.requestPayment({ uni.requestPayment({
provider: 'wxpay', provider: 'wxpay',
orderInfo :{ orderInfo :{
@ -52,12 +52,12 @@ export const Wxpay = async ({orderId,openId})=>{
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
const par = result.dataInfo; const par = result.payDataInfo;
WeixinJSBridge.invoke('getBrandWCPayRequest', { WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId : par.appId, appId : par.appId,
timeStamp : par.timeStamp, timeStamp : par.timeStamp,
nonceStr : par.nonceStr, nonceStr : par.nonceStr,
package : par.packageValue, package: par.packageValue,
signType : par.signType, signType : par.signType,
paySign : par.paySign paySign : par.paySign
}, res => { }, res => {
@ -74,8 +74,8 @@ export const Wxpay = async ({orderId,openId})=>{
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
const redirect_url = decodeURIComponent(`${ENV.staticUrl}/payResult?orderId=${orderId}&payType=wxh5`); const redirect_url = decodeURIComponent(`${ENV.VUE_APP_STATIC_URL}/payResult?orderId=${orderId}&payType=wxh5`);
window.location.href = `${result.dataInfo.payUrl}&redirect_url=${redirect_url}`; window.location.href = `${result.payDataInfo.h5Url}&redirect_url=${redirect_url}`;
} }
// #endif // #endif

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-20 16:45:27 * @Date: 2022-03-20 16:45:27
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-06 14:26:57 * @LastEditTime: 2022-06-22 19:34:13
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -38,10 +38,10 @@ export default {
...this.params ...this.params
}); });
const res = result.records.map(item => { const res = result.records.map(item => {
// item.labelList[{text:'x',code : 'recommended'},{text:'x',code : 'second_kill'}]
// //
item.seckill = false; item.seckill = false;
item.tagList = []; item.tagList = [];
item.labelList = item.labelList || [];
item.labelList.forEach(i => { item.labelList.forEach(i => {
if(i.code === 'second_kill'){ if(i.code === 'second_kill'){
item.seckill = true; item.seckill = true;

@ -0,0 +1,85 @@
<!--
* @Author: ch
* @Date: 2022-06-23 10:40:04
* @LastEditors: ch
* @LastEditTime: 2022-06-30 18:01:46
* @Description: file content
-->
<template>
<view class="follow">
<view class="follow--title">{{day}}追评:</view>
<view class="follow--ctx">{{followComment.commentContent}}</view>
<view class="follow--img" v-if="imgs.length">
<image class="follow--img-item" v-for="(item, idx) in imgs" :src="item" :key="idx" @click="preview(idx)" mode="aspectFit"/>
</view>
</view>
</template>
<script>
export default {
props : {
commentDetail : {
type : Object,
default : () => ({})
}
},
computed:{
followComment(){
return this.commentDetail.followComment || {}
},
day(){
const followTime = (new Date(this.followComment.createTime)).getTime();
const commentTime = (new Date(this.commentDetail.createTime)).getTime();
const day = Math.floor((followTime - commentTime) / (24 * 60 * 60 * 1000));
return day > 0 ? `${day}天后` : `当天`;
},
imgs (){
let urls = this.followComment.pictureUrl || '';
return urls ? urls.split(',') : [];
}
},
methods:{
preview(idx){
this.$store.commit('SET_COMMENT_PREVIEW', {
...this.commentDetail,
commentContent : this.followComment.commentContent,
pictureUrl : this.followComment.pictureUrl
});
this.$Router.push({
path : '/goodsCommentPreview',
query : {
idx
}
});
}
}
}
</script>
<style lang="scss" scoped>
.follow{
margin-top: 40rpx;
&--title{
color: $color-yellow3;
font-size: 28rpx;
}
&--ctx{
margin-top: 20rpx;
font-size: 30rpx;
line-height: 46rpx;
word-break: break-all;
}
&--img{
margin-top: 30rpx;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
&-item{
width: 210rpx;
height: 210rpx;
margin:20rpx 0;
}
}
}
</style>

@ -0,0 +1,66 @@
<!--
* @Author: ch
* @Date: 2022-06-20 14:30:45
* @LastEditors: ch
* @LastEditTime: 2022-06-28 21:14:46
* @Description: file content
-->
<template>
<view class="goods" @click="$Router.push(`/goodsDetail?id=${goods.productId}`)">
<image class="goods--img" :src="goods.productPicture" mode="aspectFit" ></image>
<view class="goods--ctx">
<view class="goods--title">{{ goods.productName }}</view>
<view class="goods--footer">
<view class="goods--sku">{{ goods.skuName }}</view>
<view><slot name="btns"></slot></view>
</view>
</view>
</view>
</template>
<script>
export default {
props : {
goods : {
type : Object,
default : ()=>({})
}
}
}
</script>
<style lang="scss" scoped>
.goods {
display: flex;
&--img {
width: 130rpx;
height: 130rpx;
margin-right: 30rpx;
}
&--ctx{
flex: 1;
overflow: hidden;
padding: 20rpx 0;
}
&--title{
font-size: 28rpx;
overflow:hidden;
text-overflow:ellipsis;
white-space: nowrap;
padding-right: 30rpx;
}
&--footer{
display: flex;
justify-content: space-between;
padding-right: 30rpx;
}
&--sku{
font-size: 24rpx;
color: #999;
margin-top: 20rpx;
}
}
</style>

@ -0,0 +1,93 @@
<!--
* @Author: ch
* @Date: 2022-06-21 15:50:01
* @LastEditors: ch
* @LastEditTime: 2022-06-30 18:00:16
* @Description: file content
-->
<template>
<view>
<view class="top">
<u-rate count="5" size="30rpx" :value="commentDetail.commentScore" activeColor="#FFA35B" readonly inactiveColor="#DDD"></u-rate>
<text class="top--time">{{ FormatDate(commentDetail.createTime, 'yyyy-mm-dd hh:ii') }}</text>
</view>
<view class="ctx">{{ commentDetail.commentContent }}</view>
<view class="img" v-if="imgs.length">
<image class="img--item" mode="aspectFit"
v-for="(item, idx) in imgs" :src="item" :key="idx" @click="preview(idx)"/>
</view>
</view>
</template>
<script>
import {FormatDate} from '@/common/utils';
export default {
props : {
commentDetail : {
type : Object,
default : () => ({})
},
imgPreview : {
type: Boolean,
default : true,
require : true
}
},
data(){
return {
curPreview : -1
}
},
computed : {
imgs (){
let urls = this.commentDetail.pictureUrl || '';
return urls ? urls.split(',') : [];
}
},
methods:{
FormatDate,
preview(idx){
if(!this.imgPreview){
return false
}
this.$store.commit('SET_COMMENT_PREVIEW', this.commentDetail);
this.$Router.push({
path : '/goodsCommentPreview',
query : {
idx
}
});
}
}
}
</script>
<style lang="scss" scoped>
.top{
display: flex;
justify-content: space-between;
margin: 20rpx 0;
&--time{
font-size: 24rpx;
color: #999;
}
}
.ctx{
font-size: 30rpx;
line-height: 46rpx;
word-break: break-all;
}
.img{
margin-top: 30rpx;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
&--item{
width: 210rpx;
height: 210rpx;
margin:20rpx 0;
}
}
</style>

@ -0,0 +1,56 @@
<!--
* @Author: ch
* @Date: 2022-06-21 15:59:23
* @LastEditors: ch
* @LastEditTime: 2022-06-30 17:57:25
* @Description: file content
-->
<template>
<view class="merchant">
<view class="merchant--title">
<text class="merchant--name">{{merchantComment.userName}}</text>
<text class="merchant--time">{{ FormatDate(merchantComment.createTime, 'yyyy-mm-dd hh:ii') }}
</text>
</view>
<view class="merchant--ctx">{{merchantComment.commentContent}}</view>
</view>
</template>
<script>
import {FormatDate} from '@/common/utils';
export default {
props : {
merchantComment : {
type : Object,
default : () => ({})
}
},
data(){
return {
}
},
methods : {
FormatDate
}
}
</script>
<style lang="scss" scoped>
.merchant{
margin-top: 40rpx;
padding: 30rpx;
background: #F5F5F5;
&--title{
display: flex;
justify-content: space-between;
margin-bottom: 24rpx;
}
&--time{
color: #999;
font-size: 24rpx;
}
&--ctx,&--name{
font-size: 26rpx;
color: #666;
}
}
</style>

@ -0,0 +1,138 @@
<!--
* @Author: ch
* @Date: 2022-06-20 16:36:14
* @LastEditors: ch
* @LastEditTime: 2022-06-30 21:06:31
* @Description: file content
-->
<template>
<view>
<view class="rate" v-if="type === COMMENT.TYPE.COMMENT">
<text class="rate--title">满意度评分</text>
<u-rate :count="5" v-model="rate" size="47rpx" activeColor="#FFA35B" inactiveColor="#DDD"></u-rate>
<text class="rate--desc">{{rateDesc}}</text>
</view>
<textarea class="textarea" placeholder="从多个维度评价,可以帮助更多想买的人哦~"
:maxlength="500" v-model="commentContent"></textarea>
<u-upload class="upload"
@afterRead="handleUpdateImg" @delete="handleDelImg"
:fileList="fileList" :maxCount="6" :previewFullImage="true">
</u-upload>
<view class="footer">
<UiButton type="solid" :disable="isVerify" @click="handleSubmit">
{{type === COMMENT.TYPE.COMMENT ? '发表评价' : '发表追评'}}
</UiButton>
</view>
</view>
</template>
<script>
import UiButton from '@/components/UiButton.vue';
import {ApiPostComment} from '@/common/api/comment';
import COMMENT from '@/common/dicts/comment';
import {uploadFileOss, HandleApiError} from '@/common/utils';
export default {
components: { UiButton },
props:{
type : {
type : String | Number,
default : COMMENT.TYPE.COMMENT
},
commentDetail : {
type : Object,
default : ()=> ({})
}
},
data(){
return {
COMMENT,
rate : 5,
commentContent : '',
fileList : []
}
},
computed:{
isVerify(){
if(this.type === COMMENT.TYPE.COMMENT){
return !this.rate || !this.commentContent.trim();
}else{
return !this.commentContent.trim();
}
},
isEdit (){
return ( this.commentContent || this.fileList.length > 0) ? true : false
},
rateDesc(){
return COMMENT.RATE_LABEL[this.rate-1];
}
},
watch:{
isEdit(){
this.$emit('editChang',this.isEdit)
}
},
methods:{
async handleSubmit(){
let data = {
commentContent : this.commentContent,
commentType : this.type,
orderProductId : this.commentDetail.orderProductId,
pictureUrl : this.fileList.map(i => i.url).join(',')
}
if(this.type === COMMENT.TYPE.COMMENT){
data.productId = this.commentDetail.productId;
data.commentScore = this.rate;
}else if(this.type === COMMENT.TYPE.FOLLOW_COMMENT){
data.originId = data.parentId = this.commentDetail.id;
}
const {error, result} = await ApiPostComment(data);
if(!HandleApiError(error)){
this.commentContent = '';
this.fileList = [];
this.$nextTick(()=>{
this.$emit('submit',result);
})
}
},
async handleUpdateImg(val){
const {error, result} = await uploadFileOss(val.file, {
configId : 'account-comment',
serviceName : 'comment'
})
if(error){
uni.$u.toast(error);
}
this.fileList.push({url : result});
},
handleDelImg(target){
this.fileList.splice(target.index, 1)
}
}
}
</script>
<style lang="scss" scoped>
.rate{
display: flex;
margin: 50rpx 0;
align-items: center;
&--title{
font-size: 28rpx;
margin-right: 30rpx;
}
&--desc{
font-size: 30rpx;
color: #999;
margin-left: 40rpx;
}
}
.textarea{
height: 200rpx;
margin-bottom: 40rpx;
}
.footer{
width: 100%;
text-align: right;
margin-top: 50rpx;
}
</style>

@ -0,0 +1,96 @@
<!--
* @Author: ch
* @Date: 2022-06-21 16:01:19
* @LastEditors: ch
* @LastEditTime: 2022-07-01 17:55:01
* @Description: file content
-->
<template>
<view class="thumb">
<view class="thumb--item" @click="handleUseful">
<u-icon name="thumb-up-fill" v-if="isLike"></u-icon>
<u-icon name="thumb-up" v-else></u-icon>
<text>{{usefulCount}}</text>
</view>
<view class="thumb--item" @click="$Router.push(`/goodsCommentDetail?id=${commentDetail.id}`)">
<u-icon name="chat"></u-icon>
<text>{{commentDetail.replyCount}}</text>
</view>
</view>
</template>
<script>
import {Debounce, HandleApiError} from '@/common/utils';
import {ApiPutCommentUseful} from '@/common/api/comment'
export default {
props : {
commentDetail : {
type : Object,
default : ()=>({})
}
},
data(){
return {
debounce : null,
isLike : false,
usefulCount : 0
}
},
watch :{
commentDetail :{
handler(){
this.isLike = this.commentDetail.isLike;
this.usefulCount = this.commentDetail.usefulCount;
},
deep:true
}
},
mounted(){
this.isLike = this.commentDetail.isLike;
// console.log('---',this.isLike,this.commentDetail.usefulCount);
this.usefulCount = this.commentDetail.usefulCount;
},
methods:{
handleUseful(){
this.isLike = !this.isLike
if(this.isLike){
this.usefulCount++;
}else{
this.usefulCount--;
}
if(!this.debounce){
this.debounce = Debounce(this.updateUseFul, 500);
}
this.debounce();
},
async updateUseFul(){
if(this.isLike === this.commentDetail.isLike){
return false
}
const {error, result} = await ApiPutCommentUseful({
commentId : this.commentDetail.id,
isLike : this.isLike
});
HandleApiError(error);
}
}
}
</script>
<style lang="scss" scoped>
.thumb{
display: flex;
justify-content: flex-end;
margin-top: 40rpx;
&--item{
display: flex;
align-items: center;
margin-left: 50rpx;
text{
font-size: 24rpx;
margin-left: 10rpx;
}
}
}
</style>

@ -0,0 +1,47 @@
<!--
* @Author: ch
* @Date: 2022-06-21 22:27:52
* @LastEditors: ch
* @LastEditTime: 2022-07-01 17:14:36
* @Description: file content
-->
<template>
<view class="comment-user">
<image class="comment-user--avatr" :src="userData.userAvatar" shape="circle"/>
<view>
<view class="comment-user--name">{{userData.userName}}</view>
<text class="comment-user--sku" v-if="userData.skuName">{{userData.skuName}}</text>
</view>
</view>
</template>
<script>
export default {
props : {
userData : {
type : Object,
default : ()=> ({})
}
}
}
</script>
<style lang="scss" scoped>
.comment-user{
display: flex;
justify-content: flex-start;
&--avatr{
width: 71rpx;
height: 71rpx;
margin-right: 17rpx;
}
&--name{
margin-top: 5rpx;
}
&--sku{
margin-top: 10rpx;
font-size: 24rpx;
color: #999;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-19 11:37:50 * @Date: 2022-04-19 11:37:50
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-05 11:08:44 * @LastEditTime: 2022-06-29 17:27:12
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -12,7 +12,7 @@
<script> <script>
import UiRadioPicker from './UiRadioPicker.vue' import UiRadioPicker from './UiRadioPicker.vue'
import { ApiPostWxPay } from '@/common/api/order'; import { ApiPostWxPay } from '@/common/api/order';
import { Wxpay } from '@/common/utils'; import { Wxpay, Alipay } from '@/common/utils';
export default { export default {
components: { UiRadioPicker }, components: { UiRadioPicker },
props : { props : {
@ -32,13 +32,19 @@ export default {
label : '微信支付', label : '微信支付',
value : 'wxpay' value : 'wxpay'
}, },
// {
// label : '',
// value : 'alipay'
// }
] ]
} }
}, },
mounted(){
// APP
if(!this.$store.state.openId){
this.options.push({
label : '支付宝支付',
value : 'alipay'
})
}
},
methods:{ methods:{
confirm(val){ confirm(val){
const orderId = this.order.orderId; const orderId = this.order.orderId;
@ -46,7 +52,8 @@ export default {
Wxpay({orderId, openId: this.$store.state.openId}); Wxpay({orderId, openId: this.$store.state.openId});
this.close(); this.close();
}else{ }else{
uni.$u.toast('暂不支持支付宝支付'); // uni.$u.toast('');
Alipay({orderId})
} }
}, },
close(){ close(){

@ -2,11 +2,11 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-31 15:42:55 * @Date: 2022-03-31 15:42:55
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-04-19 13:57:30 * @LastEditTime: 2022-06-22 14:12:46
* @Description: file content * @Description: file content
--> -->
<template> <template>
<view class="ui-white-box"> <view class="ui-white-box" @click="$emit('click')">
<slot></slot> <slot></slot>
</view> </view>
</template> </template>
@ -14,6 +14,6 @@
.ui-white-box{ .ui-white-box{
margin: 20rpx 30rpx; margin: 20rpx 30rpx;
background: $color-grey0; background: $color-grey0;
border-radius: 20rpx; border-radius: 8rpx;
} }
</style> </style>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2021-07-26 23:22:16 * @Date: 2021-07-26 23:22:16
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-23 20:55:47 * @LastEditTime: 2022-06-20 17:38:48
* @Description: file content * @Description: file content
*/ */
import Vue from 'vue'; import Vue from 'vue';
@ -13,19 +13,40 @@ import uView from 'uview-ui';
import store from '@/common/store'; import store from '@/common/store';
import {FormatSearchJson} from '@/common/utils'; import {FormatSearchJson} from '@/common/utils';
import {ApiGetOpenId, ApiGetAuthUrl} from '@/common/api/wx'; import {ApiGetOpenId, ApiGetAuthUrl} from '@/common/api/wx';
import {ApiGetCurrentUser} from '@/common/api/account';
import {Im, ImInit} from '@/common/utils'; import {Im, ImInit} from '@/common/utils';
import { ApiSktSysGetSession, ApiSktSysHeart } from './common/api/im'; import { ApiSktSysGetSession, ApiSktSysHeart } from './common/api/im';
if (store.state.token) { const socketInit = () => {
if (!store.state.userInfo.id) {
setTimeout(() => {
socketInit();
},10000)
return false;
}
// 初始化IM // 初始化IM
ImInit().then(() => { ImInit().then(() => {
// 获取到会话列表 // 获取到会话列表
Im.getSessionList({ Im.getSessionList();
content: { sysId : 1 }
});
}); });
} }
const getUserInfo = async () => {
const { error, result } = await ApiGetCurrentUser();
if (error) {
uni.$u.toast(error.message);
return false;
}
store.commit('SET_USER_INFO', result);
};
if (store.state.token) {
socketInit();
getUserInfo();
}
// 微信打开需要授权 // 微信打开需要授权
const ua = navigator ? navigator.userAgent.toLowerCase() : ''; const ua = navigator ? navigator.userAgent.toLowerCase() : '';

@ -1,6 +1,6 @@
{ {
"name" : "马士兵严选", "name" : "马士兵严选",
"appid" : "__UNI__3FB31B6", "appid" : "__UNI__5FEB250",
"description" : "", "description" : "",
"versionName" : "1.0.1", "versionName" : "1.0.1",
"versionCode" : "100", "versionCode" : "100",
@ -40,10 +40,14 @@
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>", "<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
] ],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
"minSdkVersion" : 21
}, },
/* ios */ /* ios */
"ios" : {}, "ios" : {
"dSYMs" : false
},
/* SDK */ /* SDK */
"sdkConfigs" : { "sdkConfigs" : {
"ad" : {}, "ad" : {},
@ -52,39 +56,18 @@
"__platform__" : [ "android" ], "__platform__" : [ "android" ],
"appid" : "wx17b34a4a90ef18f7", "appid" : "wx17b34a4a90ef18f7",
"UniversalLinks" : "" "UniversalLinks" : ""
},
"alipay" : {
"__platform__" : [ "android" ]
} }
} }
}, },
"icons" : { "icons" : {
"android" : { "android" : {
"hdpi" : "unpackage/res/icons/72x72.png", "hdpi" : "src/static/app-icon/72.png",
"xhdpi" : "unpackage/res/icons/96x96.png", "xhdpi" : "src/static/app-icon/96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png", "xxhdpi" : "src/static/app-icon/144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png" "xxxhdpi" : "src/static/app-icon/192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
} }
} }
} }
@ -118,20 +101,7 @@
"base" : "" "base" : ""
}, },
"devServer" : { "devServer" : {
"proxy" : { "port" : 8080
"/uc/" : {
"target" : "https://k8s-horse-gateway.mashibing.cn"
},
"/mall/" : {
"target" : "https://k8s-horse-gateway.mashibing.cn"
},
"/pay/" : {
"target" : "https://k8s-horse-gateway.mashibing.cn"
},
"/oss/" : {
"target" : "https://k8s-horse-gateway.mashibing.cn"
}
}
}, },
"optimization" : { "optimization" : {
"treeShaking" : { "treeShaking" : {

@ -10,6 +10,13 @@
"backgroundColor" : "#69ADE5" "backgroundColor" : "#69ADE5"
} }
}, },
{
"path": "pages/webView",
"aliasPath" : "/webView",
"style": {
"navigationBarTitleText": "收银台"
}
},
{ {
"path": "pages/login", "path": "pages/login",
"aliasPath" : "/login", "aliasPath" : "/login",
@ -58,6 +65,42 @@
"navigationBarTitleText": "马士兵严选" "navigationBarTitleText": "马士兵严选"
} }
}, },
{
"path": "pages/goods/enable",
"aliasPath" : "/enable",
"style": {
"navigationBarTitleText": "商品详情"
}
},
{
"path": "pages/goods/comment/list",
"aliasPath" : "/goodsCommentList",
"style": {
"navigationBarTitleText": "全部评价"
}
},
{
"path": "pages/goods/comment/otherList",
"aliasPath" : "/goodsCommentOtherList",
"style": {
"navigationBarTitleText": "全部评价"
}
},
{
"path": "pages/goods/comment/preview",
"aliasPath" : "/goodsCommentPreview",
"style": {
"navigationStyle" : "custom",
"navigationBarTitleText": "马士兵严选"
}
},
{
"path": "pages/goods/comment/detail",
"aliasPath" : "/goodsCommentDetail",
"style": {
"navigationBarTitleText": "全部评价"
}
},
{ {
"path": "pages/account/index", "path": "pages/account/index",
"aliasPath" : "/account", "aliasPath" : "/account",
@ -177,6 +220,20 @@
"navigationBarTitleText": "支付中" "navigationBarTitleText": "支付中"
} }
}, },
{
"path": "pages/order/comment/index/index",
"aliasPath" : "/comment",
"style": {
"navigationBarTitleText": "发表评价"
}
},
{
"path": "pages/order/comment/success",
"aliasPath" : "/commentSuccess",
"style": {
"navigationBarTitleText": "评价成功"
}
},
{ {
"path": "pages/order/saleAfter/saleAfterList", "path": "pages/order/saleAfter/saleAfterList",
"aliasPath" : "/saleAfterList", "aliasPath" : "/saleAfterList",

@ -3,7 +3,7 @@
components: { UiCell },: ch components: { UiCell },: ch
* @Date: 2019-08-22 19:41:20 * @Date: 2019-08-22 19:41:20
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:07 * @LastEditTime: 2022-06-28 16:38:33
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -38,6 +38,11 @@
<image class="item-icon" src="@/static/account/sh.png"/> <image class="item-icon" src="@/static/account/sh.png"/>
<view>待收货</view> <view>待收货</view>
</view> </view>
<view class="order-tabs--item" @click="$Router.push('/orderList?tab=5')">
<u-badge class="item-badge" max="99" :value="statistic.waitComment"></u-badge>
<image class="item-icon" src="@/static/account/pj.png"/>
<view>待评价</view>
</view>
</view> </view>
</view> </view>
<view class="cell"> <view class="cell">
@ -135,6 +140,10 @@ page {
top: 10rpx; top: 10rpx;
z-index: 99; z-index: 99;
border: 1px solid #fff; border: 1px solid #fff;
/* #ifndef H5 */
top: 90rpx;
/* #endif */
} }
&--cell{ &--cell{
border: 0; border: 0;

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-26 14:32:03 * @Date: 2022-03-26 14:32:03
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 22:42:35 * @LastEditTime: 2022-06-14 20:48:40
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -11,6 +11,7 @@
<view class="send" :key="item.id" v-if="item.fromId == $store.state.userInfo.id"> <view class="send" :key="item.id" v-if="item.fromId == $store.state.userInfo.id">
<text class="send--status" v-if="item.sendStatus === 'loading'"></text> <text class="send--status" v-if="item.sendStatus === 'loading'"></text>
<text class="send--status send--status__fail" v-if="item.sendStatus === 'fail'" @click="resend(item)"></text> <text class="send--status send--status__fail" v-if="item.sendStatus === 'fail'" @click="resend(item)"></text>
<template v-if="item.type == MSG_TYPE.CUSTOM"> <template v-if="item.type == MSG_TYPE.CUSTOM">
<GoodsInfo class="send--box" position="msg" v-if="item.payload.id" :goodsInfo="item.payload"/> <GoodsInfo class="send--box" position="msg" v-if="item.payload.id" :goodsInfo="item.payload"/>
<OrderInfo class="send--box" position="msg" v-if="item.payload.orderId" :orderInfo="item.payload"/> <OrderInfo class="send--box" position="msg" v-if="item.payload.orderId" :orderInfo="item.payload"/>
@ -26,6 +27,9 @@
<view class="tips" :key="item.id" v-else-if="item.type == MSG_TYPE.TIP"> <view class="tips" :key="item.id" v-else-if="item.type == MSG_TYPE.TIP">
<view class="tips--box">{{item.payload.text}}</view> <view class="tips--box">{{item.payload.text}}</view>
</view> </view>
<view class="tips" :key="item.id" v-else-if="item.type === MSG_TYPE.CUSTOM && item.payload.customType == 'transferWaiterSession'">
<view class="tips--box">现在由客服{{item.payload.toNickname}}为您服务</view>
</view>
<view class="receive" :key="item.id" v-else> <view class="receive" :key="item.id" v-else>
<image class="avatar" :src="item.fromAvatar || require('@/static/message/xt.png')" mode="widthFix"/> <image class="avatar" :src="item.fromAvatar || require('@/static/message/xt.png')" mode="widthFix"/>
<view> <view>
@ -53,9 +57,9 @@ import {Im, ToAsyncAwait} from '@/common/utils';
import {ApiGetOrderDetail} from '@/common/api/order'; import {ApiGetOrderDetail} from '@/common/api/order';
import {ApiGetGoodsDetail} from '@/common/api/goods'; import {ApiGetGoodsDetail} from '@/common/api/goods';
import UiButton from '@/components/UiButton.vue'; import UiButton from '@/components/UiButton.vue';
import Footer from './components/Footer.vue'; import Footer from './modules/Footer.vue';
import GoodsInfo from './components/GoodsInfo.vue'; import GoodsInfo from './modules/GoodsInfo.vue';
import OrderInfo from './components/OrderInfo.vue'; import OrderInfo from './modules/OrderInfo.vue';
export default { export default {
components: { UiButton, Footer, GoodsInfo, OrderInfo }, components: { UiButton, Footer, GoodsInfo, OrderInfo },
data(){ data(){
@ -80,6 +84,9 @@ export default {
return this.curSessionData ? this.curSessionData.messageList : []; return this.curSessionData ? this.curSessionData.messageList : [];
} }
}, },
destroyed(){
Im.setCurSessionId(null);
},
watch:{ watch:{
msgData(){ msgData(){
this.$nextTick(()=>{ this.$nextTick(()=>{
@ -108,12 +115,7 @@ export default {
this.orderId = this.$Route.query.orderId; this.orderId = this.$Route.query.orderId;
this.sessionId = this.$Route.query.sessionId; this.sessionId = this.$Route.query.sessionId;
if(this.sessionId){ this.socketInit();
this.getHistoryMsg();
this.readMsg();
}else{
this.createSessionMain();
}
if(this.goodsId){ if(this.goodsId){
this.getGoodsInfo(); this.getGoodsInfo();
} }
@ -129,14 +131,35 @@ export default {
}, },
methods:{ methods:{
socketInit(){
if(!Im.isOpen){
setTimeout(()=>{
this.socketInit();
}, 100)
return false;
}
if(this.sessionId){
if(!this.msgData?.length){
this.getHistoryMsg();
}
this.readMsg();
}else{
this.createSessionMain();
}
},
/** /**
* 创建会话主体 * 创建会话主体
* 如果是从商品或订单进来需要创建会话 * 如果是从商品或订单进来需要创建会话
*/ */
async createSessionMain(){ async createSessionMain(){
if(!Im.isOpen){
setTimeout(()=>this.createSessionMain(),1000);
return false;
}
const {error, result} = await ToAsyncAwait(Im.createSession({ const {error, result} = await ToAsyncAwait(Im.createSession({
content : { content : {
storeId : 1 sessionType : 3
} }
})); }));
@ -144,23 +167,24 @@ export default {
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
this.sessionId = result.content.id this.sessionId = result.content.id;
Im.setCurSessionId(this.sessionId);
this.getHistoryMsg(); this.getHistoryMsg();
this.readMsg(); // this.readMsg();
}, },
/** /**
* 获取历史消息 * 获取历史消息
*/ */
async getHistoryMsg(){ async getHistoryMsg(){
this.loading = true; if(!this.curSessionData.id){
const lastMsg = this.msgData?.length ? this.msgData[0] : {}; setTimeout(()=>{
const {error, result} = await ToAsyncAwait(Im.getHistoryMsg({ this.getHistoryMsg();
content : { }, 500)
sessionId : this.sessionId, return false;
topMessageId : lastMsg.id || null
} }
})); this.loading = true;
const {error, result} = await ToAsyncAwait(Im.getHistoryMsg());
if(error){ if(error){
uni.$u.toast(error.errMsg || error.message); uni.$u.toast(error.errMsg || error.message);
return false return false
@ -178,6 +202,7 @@ export default {
})); }));
if(error){ if(error){
uni.$u.toast(error.errMsg || error.message); uni.$u.toast(error.errMsg || error.message);
console.log(error);
return false return false
} }
@ -252,6 +277,7 @@ page{
color: #333; color: #333;
font-size: 32rpx; font-size: 32rpx;
line-height: 40rpx; line-height: 40rpx;
word-break: break-all;
} }
&__img{ &__img{
height: 140rpx; height: 140rpx;
@ -283,6 +309,7 @@ page{
color: #fff; color: #fff;
font-size: 32rpx; font-size: 32rpx;
line-height: 46rpx; line-height: 46rpx;
word-break: break-all;
} }
&__img{ &__img{
height: 140rpx; height: 140rpx;

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-05-11 11:45:08 * @Date: 2022-05-11 11:45:08
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 22:54:29 * @LastEditTime: 2022-06-14 12:55:27
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -158,11 +158,11 @@ export default {
this.msgCtx += str; this.msgCtx += str;
}, },
sendGoods(){ sendGoods(){
this.send(this.simpleGoods, MSG_TYPE.CUSTOM); this.send({...this.simpleGoods, customType:'goodsInfo'}, MSG_TYPE.CUSTOM);
this.goodsShow = false; this.goodsShow = false;
}, },
sendOrder(){ sendOrder(){
this.send(this.simpleOrder, MSG_TYPE.CUSTOM); this.send({...this.simpleOrder, customType : 'orderInfo'}, MSG_TYPE.CUSTOM);
this.orderShow = false; this.orderShow = false;
}, },
uploadImg(val){ uploadImg(val){

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 16:13:00 * @Date: 2022-03-22 16:13:00
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-27 15:32:18 * @LastEditTime: 2022-06-17 16:31:20
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -18,11 +18,14 @@
<text class="msgItem--text" v-if="item.lastMessage"> <text class="msgItem--text" v-if="item.lastMessage">
<template v-if="item.lastMessage.type == msgType.TXT">{{item.lastMessage.payload.content || item.lastMessage.payload.text}}</template> <template v-if="item.lastMessage.type == msgType.TXT">{{item.lastMessage.payload.content || item.lastMessage.payload.text}}</template>
<template v-if="item.lastMessage.type == msgType.CUSTOM"> <template v-if="item.lastMessage.type == msgType.CUSTOM">
<template v-if="item.lastMessage.payload.customType === 'orderAutoDelivery'"> <template v-if="item.lastMessage.payload.customType === 'app_push'">
{{item.lastMessage.payload.content}} {{item.lastMessage.payload.link ? '[链接]' : item.lastMessage.payload.content}}
</template>
<template v-if="item.lastMessage.payload.customType === 'transferWaiterSession'">
[客服转移]
</template> </template>
<template v-else> <template v-else>
[链接] {{item.lastMessage.payload.content || '[未知消息]'}}
</template> </template>
</template> </template>
<template v-if="item.lastMessage.type == msgType.IMG">[]</template> <template v-if="item.lastMessage.type == msgType.IMG">[]</template>
@ -40,7 +43,7 @@
<script> <script>
import BsEmpty from '../../../components/BsEmpty.vue'; import BsEmpty from '../../../components/BsEmpty.vue';
import {MSG_TYPE} from '@/common/dicts/im'; import {MSG_TYPE} from '@/common/dicts/im';
import {FormatDate} from '@/common/utils'; import {FormatDate, Im} from '@/common/utils';
export default { export default {
components: { BsEmpty }, components: { BsEmpty },
data (){ data (){
@ -56,18 +59,20 @@ export default {
}, },
computed:{ computed:{
sessionData (){ sessionData (){
return this.$store.state.imData; return this.$store.state.imData.sort((a,b) => b.updateTimeStamp - a.updateTimeStamp);
} }
}, },
methods:{ methods:{
FormatDate, FormatDate,
openMsg(item){ openMsg(item){
if(item.type === 3){ Im.setCurSessionId(item.id);
this.$Router.push(`/messageChat?sessionId=${item.id}`); if(item.type === 4){
}else{ if(JSON.parse(item.payload).type === 'system'){
this.$Router.push(`/messageSystem?sessionId=${item.id}`); this.$Router.push(`/messageSystem?sessionId=${item.id}`);
return false;
} }
}
this.$Router.push(`/messageChat?sessionId=${item.id}`);
} }
} }
} }
@ -107,6 +112,8 @@ export default {
display:-webkit-box; display:-webkit-box;
-webkit-box-orient:vertical; -webkit-box-orient:vertical;
-webkit-line-clamp:2; -webkit-line-clamp:2;
word-break: break-all;
} }
&--right{ &--right{
text-align: right; text-align: right;

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-26 14:32:03 * @Date: 2022-03-26 14:32:03
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-27 17:02:59 * @LastEditTime: 2022-06-02 18:07:09
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -21,7 +21,6 @@
<text class="msg-item--desc-link" v-if="i.shipType === 1" @click="openLink(i)" :key="i.shipContent">[]</text> <text class="msg-item--desc-link" v-if="i.shipType === 1" @click="openLink(i)" :key="i.shipContent">[]</text>
<text v-else :key="i.shipContent">{{i.shipContent}}</text> <text v-else :key="i.shipContent">{{i.shipContent}}</text>
</template> </template>
</template> </template>
</view> </view>
</view> </view>
@ -78,13 +77,7 @@ export default {
}, },
async getHistoryMsg(){ async getHistoryMsg(){
this.loading = true; this.loading = true;
const lastMsg = this.msgData?.length ? this.msgData[this.msgData.length - 1] : {}; await ToAsyncAwait(Im.getHistoryMsg());
await ToAsyncAwait(Im.getHistoryMsg({
content : {
sessionId : this.$route.query.sessionId,
topMessageId : lastMsg.id || null
}
}));
}, },
/** /**
* 把当前会话消息置为已读 * 把当前会话消息置为已读

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 15:09:06 * @Date: 2022-03-22 15:09:06
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 17:24:35 * @LastEditTime: 2022-06-23 17:45:29
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -28,6 +28,7 @@ export default {
return this.$store.state.userInfo return this.$store.state.userInfo
} }
}, },
methods:{ methods:{
logout(){ logout(){
uni.showModal({ uni.showModal({
@ -43,7 +44,7 @@ export default {
return false; return false;
} }
this.$store.commit('SET_TOKEN'); this.$store.commit('SET_TOKEN');
Im.logout(); Im.close();
this.$Router.replace('/login'); this.$Router.replace('/login');
} }
} }

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-28 15:38:23 * @Date: 2022-03-28 15:38:23
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-17 11:44:50 * @LastEditTime: 2022-06-13 20:49:32
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -38,7 +38,7 @@ export default {
nickname : this.userInfo.nickname nickname : this.userInfo.nickname
}); });
if(error){ if(error){
ui.$u.totas(error.message); uni.$u.toast(error.message);
return false; return false;
} }
this.$store.commit('SET_USER_INFO', {...this.userInfo}); this.$store.commit('SET_USER_INFO', {...this.userInfo});

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-28 15:38:23 * @Date: 2022-03-28 15:38:23
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:14 * @LastEditTime: 2022-06-13 20:59:54
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -106,7 +106,7 @@ export default {
const avatar = `${oss.host}/${oss.dir}${fileName}`; const avatar = `${oss.host}/${oss.dir}${fileName}`;
const {error, result} = await ApiPutUser({avatar}); const {error, result} = await ApiPutUser({avatar});
if(error){ if(error){
ui.$u.totas(error.message); uni.$u.toast(error.message);
return false return false
} }
this.$store.commit('SET_USER_INFO', {...this.userInfo, avatar}); this.$store.commit('SET_USER_INFO', {...this.userInfo, avatar});

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2019-08-22 19:41:20 * @Date: 2019-08-22 19:41:20
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-17 11:29:38 * @LastEditTime: 2022-05-30 17:44:51
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -10,7 +10,7 @@
</template> </template>
<script> <script>
import PageCtx from './components/PageCtx'; import PageCtx from './modules/PageCtx';
export default { export default {
components : {PageCtx}, components : {PageCtx},
onShow(){ onShow(){

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-08 18:36:14 * @Date: 2022-04-08 18:36:14
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-17 11:29:41 * @LastEditTime: 2022-05-30 17:44:55
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -10,7 +10,7 @@
</template> </template>
<script> <script>
import PageCtx from './components/PageCtx'; import PageCtx from './modules/PageCtx';
import {ApiGetCartList} from '@/common/api/cart'; import {ApiGetCartList} from '@/common/api/cart';
export default { export default {
components : {PageCtx}, components : {PageCtx},

@ -17,10 +17,11 @@
<!-- 右侧 二级分类 --> <!-- 右侧 二级分类 -->
<scroll-view class="cate-right" @scrolltolower="reachBottom" :scroll-top="scrollTop" :scroll-y="true"> <scroll-view class="cate-right" @scrolltolower="reachBottom" :scroll-top="scrollTop" :scroll-y="true">
<image class="cate-tow-img" :src="`https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/category${categoryData[curIndex].id}.jpg`"></image> <image class="cate-tow-img" v-if="curTwoCategory.adPictureUrl" :src="curTwoCategory.adPictureUrl"
@click="handleAdJump(curTwoCategory)"></image>
<!-- <view @click="onTargetGoodsList(item.id)"> --> <!-- <view @click="onTargetGoodsList(item.id)"> -->
<view class="cate-tow-group" :class="idx === categoryData[curIndex].children.length - 1 ? 'cate-tow-group__last' :''" <view class="cate-tow-group" :class="idx === curTwoCategory.children.length - 1 ? 'cate-tow-group__last' :''"
v-for="(item, idx) in categoryData[curIndex].children" :key="idx"> v-for="(item, idx) in curTwoCategory.children" :key="idx">
<text class="cate-tow-group--title">{{item.name}}</text> <text class="cate-tow-group--title">{{item.name}}</text>
<view class="cate-tow-group--item" v-for="i in item.productList" :key="i.id" <view class="cate-tow-group--item" v-for="i in item.productList" :key="i.id"
@click="$Router.push(`/goodsDetail?id=${i.id}`)"> @click="$Router.push(`/goodsDetail?id=${i.id}`)">
@ -30,9 +31,9 @@
</view> </view>
</view> </view>
<!-- </view> --> <!-- </view> -->
<BsEmpty class="empty" v-if="!categoryData[curIndex].children.length && !categoryData[curIndex].isLoading" <BsEmpty class="empty" v-if="!curTwoCategory.children.length && !curTwoCategory.isLoading"
:icon="require('@/static/common/empty_goods.png')" /> :icon="require('@/static/common/empty_goods.png')" />
<u-loadmore status="loading" v-if="categoryData[curIndex].isLoading" /> <u-loadmore status="loading" v-if="curTwoCategory.isLoading" />
</scroll-view> </scroll-view>
</view> </view>
<BsEmpty v-if="!categoryData.length && !isLoading" /> <BsEmpty v-if="!categoryData.length && !isLoading" />
@ -45,6 +46,9 @@
import {ApiGetCategoryOneList, ApiGetCategoryTwoAndGoods} from '@/common/api/goods'; import {ApiGetCategoryOneList, ApiGetCategoryTwoAndGoods} from '@/common/api/goods';
import BsEmpty from "@/components/BsEmpty"; import BsEmpty from "@/components/BsEmpty";
import UiPageHeader from '../../components/UiPageHeader.vue'; import UiPageHeader from '../../components/UiPageHeader.vue';
import { AD_LOCATION } from '@/common/dicts/ad';
import { ApiGetAdList } from '@/common/api/ad';
import { AdJump } from '@/common/utils';
export default { export default {
components: { BsEmpty, UiPageHeader }, components: { BsEmpty, UiPageHeader },
data() { data() {
@ -59,6 +63,11 @@ export default {
isLoading: true, isLoading: true,
}; };
}, },
computed:{
curTwoCategory(){
return this.categoryData[this.curIndex];
}
},
onLoad() { onLoad() {
// //
this.getCategoryData(); this.getCategoryData();
@ -94,6 +103,7 @@ export default {
item.children = []; item.children = [];
item.isLoading = true; item.isLoading = true;
this.getTwoCategoryData(item); this.getTwoCategoryData(item);
this.getTwoCategoryAd(item);
return item; return item;
}); });
this.isLoading = false; this.isLoading = false;
@ -107,6 +117,24 @@ export default {
const {error, result} = await ApiGetCategoryTwoAndGoods({categoryId : item.id}); const {error, result} = await ApiGetCategoryTwoAndGoods({categoryId : item.id});
this.$set(item, 'children', result); this.$set(item, 'children', result);
this.$set(item, 'isLoading', false); this.$set(item, 'isLoading', false);
},
async getTwoCategoryAd(item){
const {error, result} = await ApiGetAdList({
loacation : AD_LOCATION.CATEGORY_BANNER,
productCategoryId : item.id
});
if(result.length){
this.$set(item, 'adPictureUrl', result[0].pictureUrl);
this.$set(item, 'adJumpUrl', result[0].jumpUrl);
this.$set(item, 'adJumpType', result[0].jumpType);
}
},
handleAdJump(item){
console.log(item);
AdJump({
jumpUrl: item.adJumpUrl,
jumpType:item.adJumpType
});
} }
}, },
}; };

@ -0,0 +1,268 @@
<!--
* @Author: ch
* @Date: 2022-06-21 18:19:13
* @LastEditors: ch
* @LastEditTime: 2022-07-01 17:12:16
* @Description: file content
-->
<template>
<view>
<view class="box">
<BsCommentUserInfo :userData="detail"/>
<BsCommentInfo :commentDetail="detail"/>
<BsCommentFollowInfo v-if="detail.followComment" :commentDetail="detail"/>
<BsCommentGoodsInfo class="goods-info" :goods="detail" />
</view>
<view class="reply-title">全部评论( {{detail.replyCount}})</view>
<view class="reply">
<template v-if="detail.replyCount">
<view class="reply--item" v-if="detail.merchantComment">
<view class="reply--title">
<text>
{{detail.merchantComment.userName}}
</text>
<text>{{FormatDate(detail.merchantComment.createTime, 'yyyy-mm-dd hh:ii')}}</text>
</view>
<view class="reply--ctx">{{detail.merchantComment.commentContent}}</view>
</view>
<view class="reply--item" v-for="item in detail.answerCommentList" :key="item.id" @click="handleAnswer(item)">
<view class="reply--title">
<text>
{{item.userName}} {{item.parentId !== detail.id ? ` 回复 ${item.parentUserName}` : ''}}
</text>
<text>{{FormatDate(item.createTime, 'yyyy-mm-dd hh:ii')}}</text>
</view>
<view class="reply--ctx">{{item.commentContent}}</view>
</view>
</template>
<BsEmpty v-else tips="还没有人评论哦,快来抢沙发~"/>
</view>
<view class="footer">
<view class="footer--item" v-if="!detail.followComment && detail.userId === $store.state.userInfo.id"
@click="$Router.push(`/comment?commentId=${commentId}&follow=true`)">
<u-icon name="chat" size="28rpx"></u-icon>
追评
</view>
<view class="footer--item" @click="isShowAnswer = true">
<u-icon name="chat" size="28rpx"></u-icon>
评论
</view>
<view class="footer--item" :class="{'footer--item__active' : isLike}" @click="handleUseful">
<u-icon name="thumb-up" size="28rpx" :color="isLike ? '#FF875B' : ''"></u-icon>
有用<template v-if="detail.usefulCount">({{detail.usefulCount}})</template>
</view>
</view>
<template v-if="isShowAnswer" >
<view class="reply-comment--bg" @click="handleHideAnswer"></view>
<view class="reply-comment">
<view class="reply-comment--box">
<input class="reply-comment--input" maxlength="500" v-model="commentContent" :placeholder="placeholder" />
<UiButton type="gradual" :disable="!commentContent.trim()" @click="handleSubmit"></UiButton>
</view>
</view>
</template>
</view>
</template>
<script>
import BsCommentGoodsInfo from '../../../components/BsCommentGoodsInfo.vue'
import BsCommentInfo from '../../../components/BsCommentInfo.vue'
import BsCommentUserInfo from '../../../components/BsCommentUserInfo.vue'
import UiButton from '../../../components/UiButton.vue'
import {ApiGetCommentDetail, ApiPostComment, ApiPutCommentUseful} from '@/common/api/comment'
import {HandleApiError, Debounce, FormatDate} from '@/common/utils'
import COMMENT from '@/common/dicts/comment'
import BsEmpty from '../../../components/BsEmpty.vue'
import BsCommentFollowInfo from '../../../components/BsCommentFollowInfo.vue'
export default {
components: { BsCommentGoodsInfo, BsCommentInfo, UiButton, BsCommentUserInfo, BsEmpty, BsCommentFollowInfo },
data(){
return {
isShowAnswer : false,
answer : null,
commentId : this.$Route.query.id,
detail : {},
commentContent : '',
isLike : false
}
},
computed:{
placeholder(){
return this.answer ? `回复:${this.answer.userName}` : '说点什么吧?'
},
replyCount(){
}
},
onShow(){
this.getDetail();
},
methods:{
FormatDate,
async getDetail(){
const {error, result} = await ApiGetCommentDetail({
commentId : this.commentId
});
if(!HandleApiError(error,'getDetail')){
this.detail = result;
this.isLike = result.isLike || false;
this.detail.usefulCount = this.detail.usefulCount || 0;
this.detail.replyCount = this.detail.replyCount || 0;
// if(result.merchantComment){
// this.detail.answerCommentList.unshift({
// ...result.merchantComment,
// parentId : result.id
// })
// }
}
},
async handleSubmit(){
let data = {
commentContent : this.commentContent,
commentType : COMMENT.TYPE.ANSWER,
originId : this.detail.id,
parentId : this.answer ? this.answer.id : this.detail.id
}
const {error, result} = await ApiPostComment(data);
if(!HandleApiError(error)){
this.detail.answerCommentList.unshift({
...result,
userName : this.$store.state.userInfo.nickname,
parentUserName: this.answer ? this.answer.userName : ''
});
this.commentContent = '';
this.detail.replyCount++;
uni.$u.toast('评论成功!');
}
},
handleAnswer(item){
this.isShowAnswer = true;
this.answer = item;
},
handleHideAnswer(...e){
this.isShowAnswer = false;
this.answer = null;
},
handleUseful(){
this.isLike = !this.isLike
if(this.isLike){
this.detail.usefulCount++;
}else{
this.detail.usefulCount--;
}
if(!this.debounce){
this.debounce = Debounce(this.updateUseFul, 500);
}
this.debounce();
},
async updateUseFul(){
if(this.isLike === this.detail.isLike){
return false
}
const {error, result} = await ApiPutCommentUseful({
commentId : this.detail.id,
isLike : this.isLike
});
HandleApiError(error);
}
}
}
</script>
<style lang="scss">
page{
background: $color-grey1;
padding-bottom: 140rpx;
}
</style>
<style lang="scss" scoped>
.box{
background: $color-grey0;
padding: 40rpx;
}
.goods-info{
margin-top: 30rpx;
border: 1px solid #f8f8f8;
}
.reply-title{
height: 70rpx;
line-height: 70rpx;
margin-bottom:1rpx;
margin-top: 20rpx;
background: #fff;
padding: 0 40rpx;
}
.reply{
background: #fff;
padding: 0 40rpx;
overflow: hidden;
&--item{
border-bottom: 1px solid $color-grey1;
padding-top: 40rpx;
}
&--title{
display: flex;
justify-content: space-between;
text{
color: #999;
}
}
&--ctx{
margin: 26rpx 0;
line-height: 36rpx;
word-break: break-all;
}
}
.footer{
height: 124rpx;
position: fixed;
bottom: var(--window-bottom);
left: 0;
right: 0;
display: flex;
justify-content: space-around;
align-items: center;
background: #fff;
border-top: 1px solid #f8f8f8;
&--item{
display: flex;
align-items: center;
&__active{
color: $color-yellow3;
}
}
}
.reply-comment--bg{
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
z-index: 1;
}
.reply-comment{
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 2;
background: #fff;
height: 124rpx;
padding: 24rpx 40rpx;
border-top: 1px solid #f8f8f8;
&--box{
display: flex;
background: #F5F5F5;
border-radius: 38rpx;
}
&--input{
flex: 1;
padding:0 20rpx 0 40rpx;
height: 76rpx;
line-height: 76rpx;
}
}
</style>

@ -0,0 +1,203 @@
<!--
* @Author: ch
* @Date: 2022-06-21 16:51:03
* @LastEditors: ch
* @LastEditTime: 2022-06-30 22:40:31
* @Description: file content
-->
<template>
<view>
<view class="header">
<view class="tab">
<view class="tab--item" :class="{'tab--item__active' : tabActive == i.labelType}"
v-for="i in tabs" :key="i.labelType" @click="handleChangeTab(i)">
{{i.labelName}}({{i.commentCount}})
</view>
</view>
<view @click="sortChange">
<image v-if="timeSortType" class="header--sort" src="@/static/comment/sort_active.png"/>
<image v-else class="header--sort" src="@/static/comment/sort.png"/>
</view>
</view>
<view class="comment" v-for="item in list" :key="item.id" >
<view>
<BsCommentUserInfo :userData="item"/>
<BsCommentInfo :commentDetail="item"/>
<BsCommentFollowInfo v-if="item.followComment" :commentDetail="item"/>
<BsCommentMerchant v-if="item.merchantComment" :merchantComment="item.merchantComment"/>
</view>
<BsCommentThumbup :commentDetail="item"/>
</view>
<u-loadmore :status="loadingStatus" v-if="loadingStatus === 'loading'"/>
<view class="other" v-if="otherCount" @click="$Router.push(`/goodsCommentOtherList?id=${productId}`)">
已折叠{{otherCount}}条帮助不大的评价
<u-icon name="arrow-right" color="#999" size="15"></u-icon>
</view>
</view>
</template>
<script>
import BsCommentInfo from '../../../components/BsCommentInfo.vue'
import BsCommentUserInfo from '../../../components/BsCommentUserInfo.vue'
import {ApiGetCommentList, ApiGetCommentCount, ApiGetCommentTabCount} from '@/common/api/comment';
import {HandleApiError} from '@/common/utils'
import BsCommentFollowInfo from '../../../components/BsCommentFollowInfo.vue';
import BsCommentThumbup from '../../../components/BsCommentThumbup.vue';
import BsCommentMerchant from '../../../components/BsCommentMerchant.vue';
export default {
components: { BsCommentInfo, BsCommentUserInfo, BsCommentFollowInfo, BsCommentThumbup, BsCommentMerchant },
data (){
return {
list : [],
pageIndex : 1,
pageSize : 10,
productId : this.$Route.query.id,
loadingStatus : 'loading',
otherCount : 0,
timeSortType : false,
tabActive : -1,
tabs : [
{
labelName : '全部',
labelType : -1,
commentCount : 0
}
]
}
},
onLoad(){
this.getList();
this.getTabCount();
this.getCount()
},
onReachBottom(){
this.next();
},
methods:{
async getList(){
this.loadingStatus = 'loading';
const {error, result} = await ApiGetCommentList({
pageIndex : this.pageIndex,
length : this.pageSize,
productId : this.productId,
commentLabel : this.tabActive == -1 ? null : this.tabActive,
sortType : this.timeSortType ? 2 : 1,
isContent : true
});
if(!HandleApiError(error, 'getList')){
this.list = this.list.concat(result.records);
//
if(result.records.length == 0 && this.pageIndex < result.pages){
this.next();
return false;
}
//
// if(result.records.length < this.pageSize){
if(result.pages == this.pageIndex){
this.loadingStatus = 'nomore';
}
}
},
async getTabCount (){
const {error, result} = await ApiGetCommentTabCount({
productId : this.productId
});
if(!HandleApiError(error, 'getTabCount')){
this.tabs = this.tabs.concat(result.filter(i => i.commentCount > 0));
}
},
async getCount(){
const {error, result} = await ApiGetCommentCount({
productId : this.productId
});
if(!HandleApiError(error, 'getCount')){
this.otherCount = result.defaultCommentCount;
this.$set(this.tabs[0],'commentCount', result.allCommentCount)
}
},
calcDay(item, createTime){
const followTime = (new Date(item.createTime)).getTime();
const commentTime = (new Date(createTime)).getTime();
const day = Math.floor((followTime - commentTime) / (24 * 60 * 60 * 1000));
return day > 0 ? `${day}天后` : `当天`;
},
sortChange(){
this.timeSortType = !this.timeSortType;
this.list = [];
this.pageIndex = 1;
this.getList();
},
handleChangeTab(item){
this.tabActive = item.labelType;
this.pageIndex = 1;
this.list = [];
this.getList();
},
next(){
if(this.loadingStatus === 'nomore'){
return false
}
this.pageIndex++;
this.getList();
}
}
}
</script>
<style lang="scss">
page{
background: $color-grey1;
}
</style>
<style lang="scss" scoped>
.header{
background: $color-grey0;
height: 79rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 40rpx;
.tab{
display: flex;
justify-content: flex-start;
&--item{
font-size: 28rpx;
line-height: 75rpx;
margin-right: 64rpx;
&__active{
border-bottom: 4rpx solid $color-yellow3;
}
}
}
&--sort{
width: 30rpx;
height: 30rpx;
}
}
.comment{
margin-top:20rpx ;
background: $color-grey0;
padding: 40rpx;
}
.follow{
margin-top: 40rpx;
&--title{
color: $color-yellow3;
font-size: 28rpx;
}
&--ctx{
margin-top: 20rpx;
font-size: 30rpx;
line-height: 46rpx;
}
}
.other{
display: flex;
align-items: center;
color: #999;
width: 360rpx;
margin: 20rpx auto;
height: 100rpx;
}
</style>

@ -0,0 +1,109 @@
<!--
* @Author: ch
* @Date: 2022-06-21 16:51:03
* @LastEditors: ch
* @LastEditTime: 2022-06-28 20:44:13
* @Description: file content
-->
<template>
<view>
<view class="comment" v-for="item in list" :key="item.id">
<BsCommentUserInfo :userData="item"/>
<BsCommentInfo :commentDetail="item"/>
<BsCommentThumbup :commentDetail="item"/>
</view>
<u-loadmore :status="loadingStatus" v-if="loadingStatus === 'loading'"/>
</view>
</template>
<script>
import BsCommentInfo from '../../../components/BsCommentInfo.vue'
import BsCommentUserInfo from '../../../components/BsCommentUserInfo.vue'
import {ApiGetCommentList, ApiGetCommentCount, ApiGetCommentTabCount} from '@/common/api/comment';
import {HandleApiError} from '@/common/utils'
import BsCommentThumbup from '../../../components/BsCommentThumbup.vue';
export default {
components: { BsCommentInfo, BsCommentUserInfo, BsCommentThumbup },
data (){
return {
list : [],
pageIndex : 1,
pageSize : 10,
productId : this.$Route.query.id,
loadingStatus : ''
}
},
onLoad(){
this.getList();
},
onReachBottom(){
this.next();
},
methods:{
async getList(){
if(this.loadingStatus === 'loading'){
return false
}
this.loadingStatus = 'loading';
const {error, result} = await ApiGetCommentList({
pageIndex : 1,
length : this.pageSize,
productId : this.productId,
sortType : 1,
isContent : false
});
if(!HandleApiError(error, 'getList')){
this.list = result.records;
//
if(result.records.length < this.pageSize){
this.loadingStatus = 'nomore';
}
}
},
next(){
if(this.loadingStatus === 'nomore'){
return false
}
this.pageIndex++;
this.getList();
}
}
}
</script>
<style lang="scss">
page{
background: $color-grey1;
}
</style>
<style lang="scss" scoped>
.header{
background: $color-grey0;
height: 79rpx;
display: flex;
justify-content: space-between;
padding: 0 40rpx;
.tab{
display: flex;
justify-content: flex-start;
&--item{
font-size: 28rpx;
line-height: 75rpx;
margin-right: 64rpx;
&__active{
border-bottom: 4rpx solid $color-yellow3;
}
}
}
}
.comment{
margin-top:20rpx ;
background: $color-grey0;
padding: 40rpx;
}
.other{
text-align: center;
color: #999;
margin: 40rpx 0 20rpx;
}
</style>

@ -0,0 +1,187 @@
<!--
* @Author: ch
* @Date: 2022-06-22 15:15:22
* @LastEditors: ch
* @LastEditTime: 2022-07-01 17:14:16
* @Description: file content
-->
<template>
<view class="preview">
<view class="preview--top">
<image class="preview--back" src="@/static/common/back_white.png" @click="$Router.back()"></image>
<view class="preview--title">{{current + 1}}/{{imgs.length}}</view>
</view>
<u-swiper height="calc(100vh - 420rpx)" :list="imgs" :current="current"
@change="handleChange" :autoplay="false" imgMode="aspectFit" radius="0"/>
<view class="preview--footer">
<view class="preview--user">
<image class="preview--avatar" :src="data.userAvatar"></image>
<view>
<view>{{data.userName}}</view>
<view v-if="data.skuName">{{data.skuName}}</view>
</view>
</view>
<view>
<view class="preview--rate">
<u-rate count="5" size="30rpx" :value="data.commentScore" activeColor="#FFA35B" readonly inactiveColor="#DDD"></u-rate>
<text class="preview--time">{{FormatDate(data.createTime, 'yyyy-mm-dd hh:ii')}}</text>
</view>
<view class="preview--ctx">{{ data.commentContent }}</view>
</view>
<view class="thumb">
<view class="thumb--item" @click="handleUseful">
<u-icon color="#fff" :name="isLike ? 'thumb-up-fill' : 'thumb-up'"></u-icon>
<text>{{data.usefulCount || 0}}</text>
</view>
<view class="thumb--item" @click="$Router.replace(`/goodsCommentDetail?id=${data.id}`)">
<u-icon color="#fff" name="chat"></u-icon>
<text>{{data.replyCount}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import BsCommentUserInfo from '@/components/BsCommentUserInfo.vue';
import BsCommentThumbup from '../../../components/BsCommentThumbup.vue';
import {ApiPutCommentUseful} from '@/common/api/comment'
import { Debounce,FormatDate, HandleApiError} from '@/common/utils'
export default {
components: { BsCommentUserInfo,BsCommentThumbup },
data (){
return {
data : this.$store.state.comment_preview,
current : Number(this.$Route.query.idx),
isLike : false
}
},
computed : {
imgs(){
const arr = this.data.pictureUrl || [];
return arr.split(',')
}
},
onShow(){
if(!this.data.id){
this.$Router.back();
};
this.isLike = this.data.isLike
},
methods:{
FormatDate,
handleChange(idx){
this.current = idx.current
},
handleUseful(){
this.isLike = !this.isLike
if(this.isLike){
this.data.usefulCount++;
}else{
this.data.usefulCount--;
}
if(!this.debounce){
this.debounce = Debounce(this.updateUseFul, 500);
}
this.debounce();
},
async updateUseFul(){
if(this.isLike === this.data.isLike){
return false
}
const {error, result} = await ApiPutCommentUseful({
commentId : this.data.id,
isLike : this.isLike
});
HandleApiError(error);
}
}
}
</script>
<style lang="scss">
page{
background: #000;
}
</style>
<style lang="scss" scoped>
.preview{
&--top{
height: 44px;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
position: -webkit-sticky;
position: sticky;
top: var(--window-top);
z-index: 999;
}
&--back{
width: 14rpx;
height: 28rpx;
}
&--title{
flex: 1;
text-align: center;
color: #fff;
font-size: 32rpx;
}
&--footer{
padding: 40rpx;
}
&--user{
display: flex;
view{
color: #fff;
}
}
&--avatar{
width: 70rpx;
height: 70rpx;
background: #ccc;
margin-right: 20rpx;
border-radius: 50%;
}
&--rate{
display: flex;
align-items: center;
justify-content: space-between;
margin: 20rpx 0 ;
}
&--time{
color: #fff;
font-size: 24rpx;
}
&--ctx{
color: #fff;
@include ellipses(2);
line-height: 32rpx;
height: 60rpx;
}
}
.thumb{
display: flex;
justify-content: flex-end;
margin-top: 20rpx;
&--item{
display: flex;
align-items: center;
margin-left: 50rpx;
text{
font-size: 24rpx;
margin-left: 10rpx;
color: #fff;
}
}
&--icon{
font-size: 24rpx;
margin-left: 10rpx;
color: #fff;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-23 17:27:21 * @Date: 2022-03-23 17:27:21
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-19 11:24:09 * @LastEditTime: 2022-07-04 16:26:33
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -22,14 +22,16 @@
</view> </view>
<view class="goods-info--title">{{goods.name}}</view> <view class="goods-info--title">{{goods.name}}</view>
</view> </view>
<view class="select"> <view class="box">
<Service></Service> <Service></Service>
<u-cell v-if="stock > 0" label="选择" :value="curSku.name || '请选择规格'" :border="false" isLink @click="onShowSkuPopup(1)"></u-cell> <u-cell v-if="stock > 0" label="选择" :value="curSku.name || '请选择规格'" :border="false" isLink @click="onShowSkuPopup(1)"></u-cell>
<SkuPopup v-model="curSku" :visible.sync="showSkuPopup" :mode="skuMode" <SkuPopup v-model="curSku" :visible.sync="showSkuPopup" :mode="skuMode"
:goodsInfo="goods" :skuInfo="skuInfoData" :activityStatus="activityStatus"> :goodsInfo="goods" :skuInfo="skuInfoData" :activityStatus="activityStatus">
</SkuPopup> </SkuPopup>
</view> </view>
<view class="goods-desc">
<Comment v-if="commentCount" :commentList="commentList" :count="commentCount" :productId="goodsId"/>
<view class="box goods-desc">
<mp-html :content="goods.detail"/> <mp-html :content="goods.detail"/>
</view> </view>
<view class="footer--not-stock" v-if="stock === 0">~</view> <view class="footer--not-stock" v-if="stock === 0">~</view>
@ -47,20 +49,23 @@
</template> </template>
<script> <script>
import {FormatDate} from '@/common/utils'; import {FormatDate, HandleApiError} from '@/common/utils';
import {ApiGetGoodsDetail, ApiGetGoodsSkus} from '@/common/api/goods'; import {ApiGetGoodsDetail, ApiGetGoodsSkus} from '@/common/api/goods';
import SlideImage from './components/SlideImage.vue'; import {ApiGetCommentList, ApiGetCommentCount} from '@/common/api/comment';
import Service from './components/Service.vue'; import SlideImage from './modules/SlideImage.vue';
import SkuPopup from './components/SkuPopup.vue'; import Service from './modules/Service.vue';
import SkuPopup from './modules/SkuPopup.vue';
import SeckillPrice from './modules/SeckillPrice.vue';
import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'; import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html';
import UiButton from '../../../components/UiButton.vue'; import UiButton from '../../../components/UiButton.vue';
import SeckillPrice from './components/SeckillPrice.vue'; import Comment from './modules/Comment.vue';
export default { export default {
components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice}, components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice, Comment},
data(){ data(){
return { return {
// 1 // 1
stock : 1, stock : 1,
goodsId : this.$Route.query.id,
goods : { goods : {
pictureList : [] pictureList : []
}, },
@ -73,7 +78,10 @@ export default {
sku : '', sku : '',
num : 1 num : 1
}, },
productActivityVO : {} productActivityVO : {},
commentList : [],
commentCount : 0
} }
}, },
computed:{ computed:{
@ -96,8 +104,11 @@ export default {
async getGoodsDetail(){ async getGoodsDetail(){
const {query} = this.$Route; const {query} = this.$Route;
const {error, result} = await ApiGetGoodsDetail({id : query.id}); const {error, result} = await ApiGetGoodsDetail({id : query.id});
if(error){ if(HandleApiError(error, 'getGoodsDetail')){
uni.$u.toast(error.message); return false;
}
if(!result.isEnable){
this.$Router.replace('/enable')
return false; return false;
} }
this.goods = {...result, this.goods = {...result,
@ -119,15 +130,13 @@ export default {
originalPrice:result.startingPrice originalPrice:result.startingPrice
}; };
this.getGoodsSkus(); this.getGoodsSkus();
this.getComment();
this.getCommentCount();
}, },
async getGoodsSkus(){ async getGoodsSkus(){
const {query} = this.$Route; const {error, result} = await ApiGetGoodsSkus({productId : this.goodsId});
const {error, result} = await ApiGetGoodsSkus({productId : query.id}); if(!HandleApiError(error, 'getGoodsSkus')){
if(error) {
uni.$u.toast(error.message);
return false;
}
// //
this.stock = 0; this.stock = 0;
this.skuInfoData = result.map(i => { this.skuInfoData = result.map(i => {
@ -135,6 +144,28 @@ export default {
// i.attributeSymbolList = i.attributeSymbolList.split(',') // i.attributeSymbolList = i.attributeSymbolList.split(',')
return i; return i;
}); });
}
},
async getCommentCount (){
const {error, result} = await ApiGetCommentCount({
productId : this.goods.id
});
if(!HandleApiError(error, 'getCommentCount')){
this.commentCount = result.allCommentCount;
}
},
async getComment(){
const {error, result} = await ApiGetCommentList({
pageIndex : 1,
length : 2,
productId : this.goods.id,
isContent : true,
sortType : 1
});
if(!HandleApiError(error, 'getComment')){
this.commentList = result.records;
}
}, },
/** /**
* 显示/隐藏SKU弹窗 * 显示/隐藏SKU弹窗
@ -169,10 +200,7 @@ page {
width: 50rpx; width: 50rpx;
height: 50rpx; height: 50rpx;
left: 40rpx; left: 40rpx;
/* #ifdef H5 */
top: 40rpx; top: 40rpx;
/* #endif */
/* #ifndef H5 */ /* #ifndef H5 */
top: 128rpx; top: 128rpx;
/* #endif */ /* #endif */
@ -209,15 +237,12 @@ page {
} }
.select{ .box{
margin: 20rpx 30rpx; margin: 20rpx 30rpx;
background: $color-grey0; background: $color-grey0;
border-radius: 16rpx; border-radius: 16rpx;
} }
.goods-desc{ .goods-desc{
margin: 20rpx 30rpx;
background: $color-grey0;
border-radius: 16rpx;
padding: 20rpx; padding: 20rpx;
} }
.footer{ .footer{

@ -0,0 +1,90 @@
<!--
* @Author: ch
* @Date: 2022-06-21 16:23:27
* @LastEditors: ch
* @LastEditTime: 2022-06-28 11:31:02
* @Description: file content
-->
<template>
<UiWhiteBox @click="handleJumpCmment">
<view class="comment-title">
<text class="comment-title--left">用户评价({{count}})</text>
<text class="comment-title--right">查看全部</text>
</view>
<view class="comment-ctx" v-if="commentList && commentList.length">
<view v-for="item in commentList" :key="item.id">
<BsCommentUserInfo :userData="item"/>
<BsCommentInfo class="comment-ctx--item" :commentDetail="item" :imgPreview="false"/>
</view>
</view>
</UiWhiteBox>
</template>
<script>
import BsCommentInfo from '../../../../components/BsCommentInfo.vue'
import BsCommentUserInfo from '../../../../components/BsCommentUserInfo.vue'
import UiCell from '../../../../components/UiCell.vue'
import UiWhiteBox from '../../../../components/UiWhiteBox.vue'
export default {
components: { BsCommentInfo, UiCell, UiWhiteBox, BsCommentUserInfo },
props : {
count : {
type : Number,
default : 0
},
productId : {
type : Number | String,
default : 0
},
commentList : {
type : Array,
default : () => ([])
}
},
data(){
return {
}
},
methods:{
handleJumpCmment(){
let url = '/goodsCommentOtherList'
if(this.commentList.length){
url = '/goodsCommentList'
}
this.$Router.push({
path : url,
query : {
id : this.productId
}
})
}
}
}
</script>
<style lang="scss" scoped>
.comment-title{
display: flex;
justify-content: space-between;
padding:30rpx;
align-items: center;
&--left{
font-size: 30rpx;
font-weight: bold;
}
&--right{
font-size: 24rpx;
color: #999;
background: url('@/static/common/arrow.png') no-repeat right center;
background-size: 10rpx;
padding-right: 32rpx;
}
}
.comment-ctx{
padding: 0 30rpx;
&--item{
padding: 20rpx 0;
}
}
</style>

@ -0,0 +1,83 @@
<!--
* @Author: ch
* @Date: 2022-03-28 17:16:44
* @LastEditors: ch
* @LastEditTime: 2022-07-13 20:05:42
* @Description: file content
-->
<template>
<view>
<UiWhiteBox class="main">
<image class="icon" src="@/static/goods/cart.png"/>
<view class="title">商品已下架</view>
<view class="btns">
<UiButton class="btn" @click="$Router.pushTab('/')"></UiButton>
</view>
</UiWhiteBox>
<view class="recommend-title">为您推荐</view>
<BsChoiceGoods/>
</view>
</template>
<script>
import UiButton from '@/components/UiButton.vue'
import BsChoiceGoods from '../../components/BsChoiceGoods.vue'
import UiWhiteBox from '../../components/UiWhiteBox.vue'
export default {
components: { UiButton, BsChoiceGoods, UiWhiteBox }
}
</script>
<style lang="scss">
page {
background: $color-grey1;
text-align: center;
}
</style>
<style lang="scss" scoped>
.main{
padding-bottom: 40rpx;
}
.icon{
width: 400rpx;
height: 256rpx;
margin: 169rpx auto 42rpx;
}
.title{
font-size: $font-size-lg;
line-height: 44rpx;
color: $color-grey6;
}
.desc{
font-size: $font-size-sm;
line-height: 34rpx;
color: $color-grey4;
}
.btns{
margin: 74rpx 105rpx 0;
display: flex;
justify-content: space-between;
}
.recommend-title{
font-size: $font-size-lg;
text-align: center;
margin: 51rpx auto 30rpx auto;
display: flex;
align-items: center;
justify-content: space-between;
width: 500rpx;
&::after,&::before{
display: inline-block;
content: '';
width: 160rpx;
height: 2rpx;
background: linear-gradient(90deg, $color-grey3 0%, rgba(204, 204, 204, 0) 100%);
}
&::before{
background: linear-gradient(270deg, $color-grey3 0%, rgba(204, 204, 204, 0) 100%);
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-21 10:31:54 * @Date: 2022-03-21 10:31:54
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-05 16:06:41 * @LastEditTime: 2022-05-30 17:43:22
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -33,7 +33,7 @@
<script> <script>
import {ApiGetGoodsList} from '@/common/api/goods'; import {ApiGetGoodsList} from '@/common/api/goods';
import BsChoiceGoods from "@/components/BsChoiceGoods.vue"; import BsChoiceGoods from "@/components/BsChoiceGoods.vue";
import Sort from "./components/Sort.vue"; import Sort from "./modules/Sort.vue";
import UiPageHeader from '@/components/UiPageHeader.vue'; import UiPageHeader from '@/components/UiPageHeader.vue';
import UiGoodsGroup from '../../../components/UiGoodsGroup.vue'; import UiGoodsGroup from '../../../components/UiGoodsGroup.vue';
import BsEmpty from '../../../components/BsEmpty.vue'; import BsEmpty from '../../../components/BsEmpty.vue';

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2019-08-22 19:41:20 * @Date: 2019-08-22 19:41:20
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-21 16:30:22 * @LastEditTime: 2022-06-22 19:39:05
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -24,9 +24,9 @@
<view class="category"> <view class="category">
<view class="category--item" v-for="item in categoryList" :key="item.id" <view class="category--item" v-for="item in categoryList" :key="item.id"
@click="$Router.push(`/goodsList?categoryId=${item.id}`)"> @click="AdJump(item)">
<view class="category--image-box"> <view class="category--image-box">
<image class="category--image" :src="item.picture"></image> <image class="category--image" :src="item.pictureUrl"></image>
</view> </view>
<text class="category--title">{{item.name}}</text> <text class="category--title">{{item.name}}</text>
</view> </view>
@ -44,39 +44,22 @@
</template> </template>
<script> <script>
import BsChoiceGoods from '@/components/BsChoiceGoods'; import BsChoiceGoods from '@/components/BsChoiceGoods';
import Seckill from './components/Seckill'; import Seckill from './modules/Seckill';
import Pick from './components/Pick'; import Pick from './modules/Pick';
import Banner from './components/Banner'; import Banner from './modules/Banner';
import {ApiGetBannerData} from '@/common/api/index.js'; import {ApiGetBannerData} from '@/common/api/index.js';
import {ApiGetHomeSeckill} from '@/common/api/seckill.js'; import {ApiGetHomeSeckill} from '@/common/api/seckill.js';
import {ApiGetCategoryNav, ApiGetRecommendedGoodsList} from '@/common/api/goods.js'; import {ApiGetCategoryNav, ApiGetRecommendedGoodsList} from '@/common/api/goods.js';
import {ApiGetAdList} from '@/common/api/ad.js';
import {AD_LOCATION} from '@/common/dicts/ad.js';
import {AdJump} from '@/common/utils';
export default { export default {
components : {BsChoiceGoods, Pick, Banner, Seckill}, components : {BsChoiceGoods, Pick, Banner, Seckill},
data(){ data(){
return { return {
scrollTop : 0, scrollTop : 0,
bannerList: [ bannerList: [],
{ url : 'https://msb-edu-prod.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner6.jpg', categoryList : [],
link : 'https://m.mashibing.com/live/1530'
},
{ url : 'https://msb-edu-prod.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner5.jpg',
link : 'https://m.mashibing.com/course/1373/1/'
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner4.jpg',
id : 13
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/1.png',
id : 30
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/2banner.png',
id : 15
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/3banner.png',
id : 40
}
],
categoryList : [
],
recommendedGoodsList : [], recommendedGoodsList : [],
seckillData : {activityTimeVO:{}} seckillData : {activityTimeVO:{}}
@ -86,6 +69,7 @@ export default {
this.getCategoryList(); this.getCategoryList();
this.getRecommendedGoodsList(); this.getRecommendedGoodsList();
this.getSeckillList(); this.getSeckillList();
this.getBannerData();
}, },
onReachBottom(){ onReachBottom(){
this.$refs.goodsGroup.next(); this.$refs.goodsGroup.next();
@ -106,10 +90,11 @@ export default {
}, },
methods : { methods : {
async getCategoryList(){ async getCategoryList(){
const {error, result} = await ApiGetCategoryNav();
if(result){ const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_HARDCOVER
});
this.categoryList = result; this.categoryList = result;
}
}, },
async getRecommendedGoodsList(){ async getRecommendedGoodsList(){
@ -119,12 +104,19 @@ export default {
} }
}, },
async getBannerData(){
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_BANNER
});
this.bannerList = result || [];
},
async getSeckillList(){ async getSeckillList(){
const {error, result} = await ApiGetHomeSeckill(); const {error, result} = await ApiGetHomeSeckill();
if(result){ if(result){
this.seckillData = result this.seckillData = result;
}
} }
},
AdJump
} }
} }
</script> </script>

@ -2,12 +2,13 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-23 10:31:12 * @Date: 2022-03-23 10:31:12
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-21 20:09:18 * @LastEditTime: 2022-06-22 19:38:00
* @Description: file content * @Description: file content
--> -->
<template> <template>
<view class="banner"> <view class="banner">
<u-swiper bgColor="none" @click="goDetail" radius="18rpx" keyName="url" :list="data" height="240rpx" circular indicator indicatorMode="dot"></u-swiper> <u-swiper bgColor="none" radius="18rpx" height="240rpx" keyName="pictureUrl" indicatorMode="dot"
@click="goDetail" :list="data" circular indicator></u-swiper>
<view class="desc"> <view class="desc">
<view class="desc--item"> <view class="desc--item">
<image class="desc--icon" src='@/static/index/bz.png'></image> <image class="desc--icon" src='@/static/index/bz.png'></image>
@ -29,6 +30,7 @@
</view> </view>
</template> </template>
<script> <script>
import {AdJump} from '@/common/utils';
export default { export default {
data(){ data(){
return { return {
@ -38,24 +40,13 @@ export default {
props:{ props:{
data : { data : {
type : Array, type : Array,
default : [] default : ()=>([])
} }
}, },
methods:{ methods:{
goDetail(idx){ goDetail(idx){
let item = this.data[idx]; let item = this.data[idx];
if(item.link){ AdJump(item);
// #ifdef H5
window.location.href = item.link;
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(item.link);
// #endif
}else{
this.$Router.push(`/goodsDetail?id=${this.data[idx].id}`)
}
} }
} }
} }

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 15:36:46 * @Date: 2022-03-22 15:36:46
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:06 * @LastEditTime: 2022-06-13 10:20:21
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -119,9 +119,7 @@ export default {
// IM // IM
ImInit().then(() => { ImInit().then(() => {
// //
Im.getSessionList({ Im.getSessionList();
content: { sysId : 1 }
});
}); });
this.goBack(); this.goBack();

@ -0,0 +1,155 @@
<!--
* @Author: ch
* @Date: 2022-06-20 14:55:54
* @LastEditors: ch
* @LastEditTime: 2022-06-30 23:43:00
* @Description: file content
-->
<template>
<view>
<view class="box" v-for="(item, idx) in list" :key="item.productId">
<BsCommentGoodsInfo :goods="item" />
<BsCommentSubmit v-if="!item.id" :commentDetail="item" :type="COMMENT.TYPE.COMMENT"
@submit="submitComment($event,idx)" @editChang="editChange($event, idx)"/>
<!-- 已评价过显示详情 -->
<template v-else>
<BsCommentInfo :commentDetail="item" v-if="!isFollow"/>
<SubmitFollowComment :commentDetail="item"
@submit="submitFollowComment($event, idx)"
@editChange="editChange($event, idx)" :isFollow="isFollow"/>
<BsCommentMerchant v-if="item.merchantComment && !isFollow" :merchantComment="item.merchantComment"/>
<BsCommentThumbup :commentDetail="item" v-if="!isFollow"/>
</template>
</view>
</view>
</template>
<script>
import { ApiGetOrderCommentDetail,ApiGetCommentDetail } from "@/common/api/comment";
import UiWhiteBox from "@/components/UiWhiteBox.vue";
import UiButton from "@/components/UiButton.vue";
import BsCommentSubmit from "@/components/BsCommentSubmit.vue";
import BsCommentGoodsInfo from '@/components/BsCommentGoodsInfo.vue';
import BsCommentInfo from '@/components/BsCommentInfo.vue';
import BsCommentMerchant from '@/components/BsCommentMerchant.vue';
import BsCommentThumbup from '@/components/BsCommentThumbup.vue';
import SubmitFollowComment from './modules/SubmitFollowComment.vue';
import COMMENT from '@/common/dicts/comment';
const SOURCE = ['goodsComment','orderList','orderDetail','comment']
export default {
components: {
UiWhiteBox,
UiButton,
BsCommentSubmit,
BsCommentGoodsInfo,
BsCommentInfo,
BsCommentMerchant,
BsCommentThumbup,
SubmitFollowComment,
},
data() {
const query = this.$Route.query;
return {
COMMENT,
list: [],
isFollow : query.follow == 'true' ? true : false,
orderId: query.orderId,
commentId : query.commentId
};
},
onLoad() {
if(this.orderId){
this.getOrderCommentDetail();
}else if(this.commentId){
this.getCommentDetail()
}
uni.setNavigationBarTitle({
title : this.isFollow ? '发表追评' : '发表评价'
});
},
beforeRouteLeave(to, from, next) {
if(this.list.findIndex(i => i.isEdit) > -1 &&
!(to.aliasPath == '/goodsCommentPreview' || to.fullPath == '/preview-image')){
uni.showModal({
content : '你正在进行商品评价,退出后评价的内容将不保存!',
cancelColor : '#999',
confirmColor : '#3A83FB',
success: async ({confirm}) => {
if(confirm){
next()
}
}
});
}else{
next();
}
},
methods: {
async getOrderCommentDetail() {
const { error, result } = await ApiGetOrderCommentDetail({
orderId: this.orderId,
});
if (error) {
uni.$u.toast(error.message);
return false;
}
this.list = result;
},
/**
* 按评论查询追评时用
*/
async getCommentDetail(){
const {error, result} = await ApiGetCommentDetail({
commentId : this.commentId
});
if (error) {
uni.$u.toast(error.message);
return false;
}
this.list = [result];
},
getFollowType(item){
let type= 'info'
//
if(this.isFollow){
type = 'form'
}
return type;
},
submitComment(result, idx){
this.$set(this.list, idx, {...this.list[idx],...result});
if(this.list.findIndex(i => !i.id) > -1){
uni.$u.toast('评论成功~');
}else{
this.$Router.replace('/commentSuccess');
}
},
editChange(isEdit, idx){
this.$set(this.list[idx], 'isEdit', isEdit);
},
submitFollowComment(result, idx){
this.$set(this.list[idx],'followComment',{
...this.list[idx].followComment,
...result
});
}
},
};
</script>
<style lang="scss">
page {
background: $color-grey1;
}
</style>
<style lang="scss" scoped>
.box{
background: $color-grey0;
margin-bottom: 20rpx;
padding:40rpx;
}
</style>

@ -0,0 +1,74 @@
<!--
* @Author: ch
* @Date: 2022-06-20 16:36:41
* @LastEditors: ch
* @LastEditTime: 2022-06-29 20:32:02
* @Description: file content
-->
<template>
<view class="follow">
<BsCommentFollowInfo v-if="commentDetail.followComment"
:commentDetail="commentDetail" />
<template v-else>
<UiButton type="primaryLine" @click="showInput = true" v-if="!showInput"></UiButton>
<template v-else>
<BsCommentSubmit :commentDetail="commentDetail" :type="COMMENT.TYPE.FOLLOW_COMMENT"
@submit="handleSubmit" @editChang="handleEditChange"/>
</template>
</template>
</view>
</template>
<script>
import UiButton from '@/components/UiButton.vue'
import BsCommentFollowInfo from '@/components/BsCommentFollowInfo.vue';
import BsCommentSubmit from '@/components/BsCommentSubmit.vue';
import COMMENT from '@/common/dicts/comment';
export default {
components: { UiButton, BsCommentFollowInfo, BsCommentSubmit },
props : {
commentDetail : {
type : Object,
default : () => ({})
},
isFollow : {
type : Boolean,
default : false
}
},
data(){
return {
showInput : this.isFollow,
COMMENT,
}
},
computed:{
},
methods:{
async handleSubmit(data){
this.$emit('submit',data);
},
handleEditChange(data){
this.$emit('editChange',data);
}
}
}
</script>
<style lang="scss" scoped>
.follow{
margin-top: 40rpx;
&--title{
color: $color-yellow3;
font-size: 28rpx;
}
&--ctx{
margin-top: 20rpx;
font-size: 30rpx;
line-height: 46rpx;
}
}
.footer{
text-align: right;
}
</style>

@ -0,0 +1,137 @@
<!--
* @Author: ch
* @Date: 2022-06-21 15:32:28
* @LastEditors: ch
* @LastEditTime: 2022-06-30 17:23:32
* @Description: file content
-->
<template>
<view class="main">
<view class="ctx">
<image class="icon" src="@/static/order/paySuccess.png"/>
<view class="title">评价成功</view>
<view class="btns">
<UiButton class="btn" @click="$Router.back()"></UiButton>
</view>
</view>
<view class="await" v-if="goodsList.length">
<view class="await--title">这些宝贝还在等你的评价哦~</view>
<BsCommentGoodsInfo class="await--goods" :goods="item" v-for="item in goodsList" :key="item.productId">
<UiButton slot="btns" size="small" type="primaryLine"
@click="$Router.push(`/comment?commentId=${item.orderId}`)">
{{item.commentStatus == 1 ? '评价' : '追评'}}
</UiButton>
</BsCommentGoodsInfo>
</view>
<view class="recommend-title">为您推荐</view>
<BsChoiceGoods></BsChoiceGoods>
</view>
</template>
<script>
import UiButton from '@/components/UiButton.vue'
import BsChoiceGoods from '../../../components/BsChoiceGoods.vue';
import {ApiGetCommentOrderDetailList} from '@/common/api/order';
import {HandleApiError} from '@/common/utils'
import BsCommentGoodsInfo from '../../../components/BsCommentGoodsInfo.vue';
export default {
components: { UiButton, BsChoiceGoods, BsCommentGoodsInfo },
data(){
return {
goodsList : []
}
},
onLoad(){
this.getAwaitGoodsList();
},
methods:{
async getAwaitGoodsList (){
const {error, result} = await ApiGetCommentOrderDetailList({
length:2,
pageIndex : 1
});
if(!HandleApiError(error, 'getAwaitGoodsList')){
this.goodsList = result.records.map(item => {
return {
productPicture : item.productImageUrl,
productName : item.productName,
skuName : item.skuDescribe,
commentStatus : item.commentStatus,
orderId : item.orderId
}
});
}
}
}
}
</script>
<style lang="scss">
page{
background: $color-grey1;
}
</style>
<style lang="scss" scoped>
.main {
text-align: center;
}
.ctx{
background: $color-grey0;
padding-bottom: 40rpx;
.icon{
width: 400rpx;
height: 256rpx;
margin: 169rpx auto 42rpx;
}
.title{
font-size: $font-size-lg;
line-height: 44rpx;
color: $color-grey6;
}
.desc{
font-size: $font-size-sm;
line-height: 34rpx;
color: $color-grey4;
}
.btns{
margin: 74rpx 105rpx 0;
display: flex;
justify-content: space-between;
}
}
.await{
margin-top: 20rpx;
background: $color-grey0;
&--title{
text-align: left;
padding: 40rpx;
border-bottom: 1px solid #f8f8f8;
}
&--goods{
padding: 20rpx 40rpx;
text-align: left;
}
}
.recommend-title{
font-size: $font-size-lg;
text-align: center;
margin: 51rpx auto 30rpx auto;
display: flex;
align-items: center;
justify-content: space-between;
width: 500rpx;
&::after,&::before{
display: inline-block;
content: '';
width: 160rpx;
height: 2rpx;
background: linear-gradient(90deg, $color-grey3 0%, rgba(204, 204, 204, 0) 100%);
}
&::before{
background: linear-gradient(270deg, $color-grey3 0%, rgba(204, 204, 204, 0) 100%);
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-31 14:26:09 * @Date: 2022-03-31 14:26:09
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-26 17:13:33 * @LastEditTime: 2022-06-22 11:22:41
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -29,7 +29,7 @@
</template> </template>
</UiGoodsInfo> </UiGoodsInfo>
</UiWhiteBox> </UiWhiteBox>
<LogisitcsInfo v-if="orderInfo.orderType !== ORDER_TYPE.VIRTUAL" <LogisitcsInfo v-if="orderInfo.orderType !== ORDER.TYPE.VIRTUAL"
:logisitcsInfo="orderInfo.logistics" :orderId="orderInfo.orderId"/> :logisitcsInfo="orderInfo.logistics" :orderId="orderInfo.orderId"/>
<OrderInfo :orderInfo="orderInfo" /> <OrderInfo :orderInfo="orderInfo" />
<Operation :orderInfo="orderInfo" v-if="orderInfo.orderStatus !== 3"></Operation> <Operation :orderInfo="orderInfo" v-if="orderInfo.orderStatus !== 3"></Operation>
@ -40,16 +40,16 @@ import UiGoodsInfo from '@/components/UiGoodsInfo.vue';
import UiWhiteBox from '@/components/UiWhiteBox.vue'; import UiWhiteBox from '@/components/UiWhiteBox.vue';
import UiButton from '@/components/UiButton.vue'; import UiButton from '@/components/UiButton.vue';
import {ApiGetOrderDetail, ApiPutCancelOrder} from '@/common/api/order'; import {ApiGetOrderDetail, ApiPutCancelOrder} from '@/common/api/order';
import StatusTips from './components/StatusTips.vue'; import StatusTips from './modules/StatusTips.vue';
import OrderInfo from './components/OrderInfo.vue'; import OrderInfo from './modules/OrderInfo.vue';
import LogisitcsInfo from './components/LogisitcsInfo.vue'; import LogisitcsInfo from './modules/LogisitcsInfo.vue';
import Operation from './components/Operation.vue'; import Operation from './modules/Operation.vue';
import {ORDER_TYPE} from '@/common/dicts/order' import ORDER from '@/common/dicts/order'
export default { export default {
components: { UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, OrderInfo, LogisitcsInfo, Operation }, components: { UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, OrderInfo, LogisitcsInfo, Operation },
data(){ data(){
return { return {
ORDER_TYPE, ORDER,
orderInfo : { orderInfo : {
products:[], products:[],
logistics:{} logistics:{}
@ -79,7 +79,7 @@ export default {
this.getOrderInfo(); this.getOrderInfo();
}, },
handleSaleAfter(item){ handleSaleAfter(item){
if(this.orderInfo.orderType === ORDER_TYPE.VIRTUAL){ if(this.orderInfo.orderType === ORDER.TYPE.VIRTUAL){
uni.$u.toast('虚拟商品的订单不满足退款要求,不支持申请售后,如有问题请联系客服。'); uni.$u.toast('虚拟商品的订单不满足退款要求,不支持申请售后,如有问题请联系客服。');
}else{ }else{
this.$Router.push(`/saleAfterSelect?id=${item.orderProductId}`) this.$Router.push(`/saleAfterSelect?id=${item.orderProductId}`)

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-15 17:46:10 * @Date: 2022-04-15 17:46:10
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-27 11:13:24 * @LastEditTime: 2022-07-13 18:20:38
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -13,10 +13,17 @@
<UiButton class="footer--btn" v-if="orderInfo.orderStatus === 2" @click="service"></UiButton> <UiButton class="footer--btn" v-if="orderInfo.orderStatus === 2" @click="service"></UiButton>
<!-- 已发货可以确认收货 --> <!-- 已发货可以确认收货 -->
<UiButton class="footer--btn" v-if="orderInfo.orderStatus === 4" type="gradual" @click="receive"></UiButton> <UiButton class="footer--btn" v-if="orderInfo.orderStatus === 4" type="gradual" @click="receive"></UiButton>
<UiButton class="footer--btn" type="primaryLine" v-if="orderInfo.orderStatus === ORDER.STATUS.FINISH_TAKE_GOODS"
@click="$Router.push(`/comment?orderId=${orderInfo.orderId}`)">去评价</UiButton>
<UiButton size="min" type="primaryLine" v-if="orderInfo.orderStatus === ORDER.STATUS.FINISH"
@click="$Router.push(`/comment?orderId=${orderInfo.orderId}&follow=true`)">去追评</UiButton>
<!-- 待支付可以取消支付订单 --> <!-- 待支付可以取消支付订单 -->
<template v-if="orderInfo.orderStatus === 1"> <template v-if="orderInfo.orderStatus === 1">
<UiButton class="footer--btn" @click="cancelShow = true">取消订单</UiButton> <UiButton class="footer--btn" @click="cancelShow = true">取消订单</UiButton>
<UiButton class="footer--btn" type="gradual" @click="payShow = true">去支付</UiButton> <UiButton class="footer--btn" type="gradual" @click="handlePay"></UiButton>
</template> </template>
<u-popup class="cancel" :show="cancelShow" @close="closeCancel" round="16rpx" closeable> <u-popup class="cancel" :show="cancelShow" @close="closeCancel" round="16rpx" closeable>
<view class="cancel--title">取消订单原因</view> <view class="cancel--title">取消订单原因</view>
@ -42,14 +49,17 @@
<UiButton type="gradual" :disabed="cancelValue == 0" @click="cancelOrder"></UiButton> <UiButton type="gradual" :disabed="cancelValue == 0" @click="cancelOrder"></UiButton>
</view> </view>
</u-popup> </u-popup>
<BsPay class="modal" :show.sync="payShow" :order="orderInfo"></BsPay> <!-- <BsPay class="modal" :show.sync="payShow" :order="orderInfo"></BsPay> -->
</view> </view>
</template> </template>
<script> <script>
import UiButton from '@/components/UiButton.vue' import UiButton from '@/components/UiButton.vue'
import UiCell from '@/components/UiCell.vue' import UiCell from '@/components/UiCell.vue'
import {ApiPutCancelOrder,ApiPutOrderReceive} from '@/common/api/order' import {ApiPutCancelOrder,ApiPutOrderReceive} from '@/common/api/order';
import BsPay from '../../../../components/BsPay.vue' import {ApiPostCashierPrepay} from '@/common/api/pay';
import BsPay from '../../../../components/BsPay.vue';
import ORDER from '@/common/dicts/order';
const ENV = process.env;
export default { export default {
components: { UiButton, UiCell, BsPay }, components: { UiButton, UiCell, BsPay },
props : { props : {
@ -60,11 +70,10 @@ export default {
}, },
data(){ data(){
return { return {
ORDER,
// //
cancelShow : false, cancelShow : false,
cancelValue : 0, cancelValue : 0,
//
payShow : false
} }
}, },
methods : { methods : {
@ -77,16 +86,16 @@ export default {
this.cancelValue = val; this.cancelValue = val;
}, },
async cancelOrder(){ async cancelOrder(){
const ooderId = this.$Route.query.id; const orderId = this.orderInfo.orderId;
const {error, result} = await ApiPutCancelOrder({ const {error, result} = await ApiPutCancelOrder({
cancelReasonType : this.cancelValue, cancelReasonType : this.cancelValue,
orderId : ooderId orderId : orderId
}); });
if(error){ if(error){
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
this.$Router.replace(`/orderDetail?id=${ooderId}`); this.$Router.replace(`/orderDetail?id=${orderId}`);
// //
}, },
/** /**
@ -100,39 +109,49 @@ export default {
success: async ({confirm}) => { success: async ({confirm}) => {
if(confirm){ if(confirm){
const {error} = await ApiPutOrderReceive({ const {error} = await ApiPutOrderReceive({
orderId : this.$Route.query.id orderId : this.orderInfo.orderId
}); });
if(error){ if(error){
uni.$toast(error.message); uni.$toast(error.message);
return false; return false;
} }
this.$Router.push('/orderSuccess'); this.$Router.push(`/orderSuccess?orderId=${this.orderInfo.orderId}`);
} }
} }
}) })
// this.$msb.confirm({
// content : '',
// confirm : async ()=>{
// const {error} = await ApiPutOrderReceive({
// orderId : this.$Route.query.id
// });
// if(error){
// uni.$toast(error.message);
// return false;
// }
// this.$Router.push('/orderSuccess');
// }
// })
}, },
service(){ service(){
// uni.$u.toast('')
this.$Router.push({ this.$Router.push({
path : '/messageChat', path : '/messageChat',
query : { query : {
orderId : this.orderInfo.orderId orderId : this.orderInfo.orderId
} }
}) })
},
async handlePay(){
let payType = 'wxjsapi'
if(!this.$store.state.openId){
payType = 'h5'
}
const {error, result} = await ApiPostCashierPrepay({
orderId:this.orderInfo.orderId,
returnUrl : `${ENV.VUE_APP_STATIC_URL}/payResult?orderId=${this.orderInfo.orderId}&payType=${payType}`
});
if(error){
uni.$u.toast(error.message);
return false;
}
// #ifdef H5
window.location.href = result.wapCashierUrl;
// #endif
// #ifndef H5
this.$Router.push(`/webView?url=${encodeURIComponent(result.wapCashierUrl)}`);
// #endif
} }
} }
} }

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-31 17:53:43 * @Date: 2022-03-31 17:53:43
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-05 20:43:19 * @LastEditTime: 2022-06-28 16:24:52
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -35,6 +35,8 @@ export default {
'5' : {name:'已收货', icon: require('@/static/order/fh.png')}, '5' : {name:'已收货', icon: require('@/static/order/fh.png')},
// //
'6' : {name:'交易成功', icon: require('@/static/order/cg.png')}, '6' : {name:'交易成功', icon: require('@/static/order/cg.png')},
//
'7' : {name:'交易成功', icon: require('@/static/order/cg.png')},
}, },
ctxCon : {}, ctxCon : {},
startSecondNum : 0, startSecondNum : 0,

@ -2,13 +2,13 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-22 10:58:24 * @Date: 2022-03-22 10:58:24
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:16 * @LastEditTime: 2022-07-13 18:21:13
* @Description: file content * @Description: file content
--> -->
<template> <template>
<view> <view>
<view class="tabs"> <view class="tabs">
<text :class="item.key === currentTabKey && 'tabs__active'" <text :class="item.key == currentTabKey && 'tabs__active'"
v-for="item in tabListData" :key="item.key" @click="changeTab(item.key)"> v-for="item in tabListData" :key="item.key" @click="changeTab(item.key)">
{{item.name}}</text> {{item.name}}</text>
</view> </view>
@ -19,7 +19,7 @@
<view class="orders" v-for="item in orderListData" :key="item.orderId"> <view class="orders" v-for="item in orderListData" :key="item.orderId">
<view class="orders--title"> <view class="orders--title">
<text class="orders--name">官方自营</text> <text class="orders--name">官方自营</text>
<text class="orders--status" :class="[1,3].includes(item.orderStatus) && 'orders--status__warn'">{{item.orderStatusDesc}}</text> <text class="orders--status" :class="[ORDER.STATUS.AWAIT_PAY,ORDER.STATUS.FINISH_PAY].includes(item.orderStatus) && 'orders--status__warn'">{{item.orderStatusDesc}}</text>
</view> </view>
<UiGoodsInfoMax v-for="item in item.products" :key="item.orderProductId" <UiGoodsInfoMax v-for="item in item.products" :key="item.orderProductId"
:data="item" @click="$Router.push(`/orderDetail?id=${item.orderId}`)" /> :data="item" @click="$Router.push(`/orderDetail?id=${item.orderId}`)" />
@ -32,39 +32,49 @@
<view class="orders--footer"> <view class="orders--footer">
<UiButton size="min" type="gradual" <UiButton size="min" type="gradual"
v-if="item.orderStatus === 1" @click="pay(item)">去支付</UiButton> v-if="item.orderStatus === ORDER.STATUS.AWAIT_PAY" @click="handlePay(item)">去支付</UiButton>
<UiButton size="min" v-if="[2,3].includes(item.orderStatus)" <UiButton size="min" v-if="[ORDER.STATUS.CLOSE,ORDER.STATUS.AWAIT_PAY].includes(item.orderStatus)"
@click="$Router.push(`/orderDetail?id=${item.orderId}`)">查看详情</UiButton> @click="$Router.push(`/orderDetail?id=${item.orderId}`)">查看详情</UiButton>
<UiButton size="min" v-if="item.orderStatus >= 4" <UiButton size="min" v-if="item.orderStatus >= ORDER.STATUS.FINISH_SEND_GOODS"
@click="$Router.push(`/logisitcsInfo?orderId=${item.orderId}`)">查看物流</UiButton> @click="$Router.push(`/logisitcsInfo?orderId=${item.orderId}`)">查看物流</UiButton>
<UiButton size="min" type="gradual" v-if="item.orderStatus === 4" @click="receive(item)"></UiButton> <UiButton size="min" type="primaryLine"
v-if="item.orderStatus === ORDER.STATUS.FINISH_TAKE_GOODS"
@click="$Router.push(`/comment?orderId=${item.orderId}`)">去评价</UiButton>
<UiButton size="min" type="primaryLine"
v-if="item.orderStatus === ORDER.STATUS.FINISH"
@click="$Router.push(`/comment?orderId=${item.orderId}&follow=true`)">去追评</UiButton>
<UiButton size="min" type="gradual" v-if="item.orderStatus === ORDER.STATUS.FINISH_SEND_GOODS" @click="receive(item)"></UiButton>
</view> </view>
</view> </view>
<u-loadmore :status="loadingStatus" v-if="loadingStatus === 'loading'"/> <u-loadmore :status="loadingStatus" v-if="loadingStatus !== 'nomore'"/>
<BsPay :show.sync="payShow" :order="payOrder"></BsPay> <!-- <BsPay :show.sync="payShow" :order="payOrder"></BsPay> -->
</view> </view>
</template> </template>
<script> <script>
import BsEmpty from '@/components/BsEmpty.vue'; import BsEmpty from '@/components/BsEmpty.vue';
import UiButton from '@/components/UiButton.vue'; import UiButton from '@/components/UiButton.vue';
import { ApiGetOrderList, ApiPutOrderReceive } from '@/common/api/order'; import { ApiGetOrderList, ApiPutOrderReceive } from '@/common/api/order';
import {ApiPostCashierPrepay} from '@/common/api/pay';
import BsPay from '../../components/BsPay.vue'; import BsPay from '../../components/BsPay.vue';
import UiGoodsInfo from '../../components/UiGoodsInfo.vue'; import UiGoodsInfo from '../../components/UiGoodsInfo.vue';
import UiGoodsInfoMax from '../../components/UiGoodsInfoMax.vue'; import UiGoodsInfoMax from '../../components/UiGoodsInfoMax.vue';
import UiMoney from '../../components/UiMoney.vue'; import UiMoney from '../../components/UiMoney.vue';
import ORDER from '@/common/dicts/order';
const ENV = process.env;
export default { export default {
components: { BsEmpty, UiButton, BsPay, UiGoodsInfo, UiGoodsInfoMax, UiMoney }, components: { BsEmpty, UiButton, BsPay, UiGoodsInfo, UiGoodsInfoMax, UiMoney },
data () { data () {
return { return {
ORDER,
tabListData : [ tabListData : [
{key : '-1', name : '全部'}, {key : '-1', name : '全部'},
{key : '1', name : '待付款'}, {key : ORDER.STATUS.AWAIT_PAY, name : '待付款'},
{key : '3', name : '待发货'}, {key : ORDER.STATUS.FINISH_PAY, name : '待发货'},
{key : '4', name : '待收货'} {key : ORDER.STATUS.FINISH_SEND_GOODS, name : '待收货'},
// {key : '6', name : ''} {key : ORDER.STATUS.FINISH_TAKE_GOODS, name : '待评价'}
], ],
currentTabKey : this.$Route.query.tab || '-1', currentTabKey : this.$Route.query.tab || '-1',
orderListData : [], orderListData : [],
@ -72,12 +82,11 @@ export default {
pageIndex : 1, pageIndex : 1,
pageSize : 10, pageSize : 10,
payShow : false,
payOrder : null payOrder : null
} }
}, },
onLoad(){ onLoad(){
this.getOrderList() this.getOrderList();
}, },
onReachBottom(){ onReachBottom(){
this.next(); this.next();
@ -87,6 +96,9 @@ export default {
* 切换tab 拉取当前分类第一页数据 * 切换tab 拉取当前分类第一页数据
*/ */
changeTab(key){ changeTab(key){
if(this.loadingStatus == 'loading' || this.currentTabKey == key){
return false;
}
this.currentTabKey = key; this.currentTabKey = key;
this.pageIndex = 1; this.pageIndex = 1;
this.orderListData = []; this.orderListData = [];
@ -103,6 +115,7 @@ export default {
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
this.loadingStatus = 'finish';
// //
if(result.records.length < this.pageSize){ if(result.records.length < this.pageSize){
this.loadingStatus = 'nomore'; this.loadingStatus = 'nomore';
@ -122,9 +135,25 @@ export default {
/** /**
* 立即支付 * 立即支付
*/ */
pay(item){ async handlePay(item){
this.payShow = true;
this.payOrder = item; let payType = 'wxjsapi'
if(!this.$store.state.openId){
payType = 'h5'
}
const {error, result} = await ApiPostCashierPrepay({
orderId:item.orderId,
returnUrl : `${ENV.VUE_APP_STATIC_URL}/payResult?orderId=${item.orderId}&payType=${payType}`
});
// #ifdef H5
window.location.href = result.wapCashierUrl
// #endif
// #ifndef H5
this.$Router.push(`/webView?url=${encodeURIComponent(result.wapCashierUrl)}`);
// #endif
}, },
/** /**
@ -144,7 +173,7 @@ export default {
uni.$toast(error.message); uni.$toast(error.message);
return false; return false;
} }
this.$Router.push('/orderSuccess') this.$Router.push(`/orderSuccess?orderId=${item.orderId}`)
} }
} }
}) })

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-18 15:28:14 * @Date: 2022-04-18 15:28:14
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-17 17:55:56 * @LastEditTime: 2022-06-22 11:22:21
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -11,7 +11,7 @@
<UiGoodsInfo :class="idx === orderInfo.products.length-1 ? 'goods-info__last' : ''" :key="item.orderProductId" <UiGoodsInfo :class="idx === orderInfo.products.length-1 ? 'goods-info__last' : ''" :key="item.orderProductId"
v-for="(item, idx) in orderInfo.products" :data="item"></UiGoodsInfo> v-for="(item, idx) in orderInfo.products" :data="item"></UiGoodsInfo>
</UiWhiteBox> </UiWhiteBox>
<UiWhiteBox class="company"> <UiWhiteBox class="company" v-if="orderInfo.orderType !== ORDER.TYPE.VIRTUAL">
<text class="company--name">{{orderInfo.companyName}}</text> <text class="company--name">{{orderInfo.companyName}}</text>
<view class="company--no"> <view class="company--no">
<text>{{orderInfo.trackingNo}}</text> <text>{{orderInfo.trackingNo}}</text>
@ -38,10 +38,12 @@ import UiGoodsInfo from '@/components/UiGoodsInfo.vue'
import UiWhiteBox from '@/components/UiWhiteBox.vue' import UiWhiteBox from '@/components/UiWhiteBox.vue'
import {ApiGetOrderLogistics} from '@/common/api/order'; import {ApiGetOrderLogistics} from '@/common/api/order';
import UiCopy from '../../components/UiCopy.vue'; import UiCopy from '../../components/UiCopy.vue';
import ORDER from '@/common/dicts/order';
export default { export default {
components: { UiWhiteBox, UiGoodsInfo, UiCopy }, components: { UiWhiteBox, UiGoodsInfo, UiCopy },
data(){ data(){
return { return {
ORDER,
orderInfo : {} orderInfo : {}
} }
}, },

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-28 17:16:44 * @Date: 2022-03-28 17:16:44
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-04-29 23:03:47 * @LastEditTime: 2022-06-28 16:46:43
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -10,7 +10,8 @@
<image class="icon" src="@/static/order/paySuccess.png"/> <image class="icon" src="@/static/order/paySuccess.png"/>
<view class="title">交易成功</view> <view class="title">交易成功</view>
<view class="btns"> <view class="btns">
<UiButton class="btn" type="primaryLine" @click="$Router.replaceAll('/')"></UiButton> <UiButton class="btn" @click="$Router.replaceAll('/')"></UiButton>
<UiButton class="btn" type="primaryLine" @click="$Router.replace(`/comment?orderId=${orderId}`)"></UiButton>
</view> </view>
</view> </view>
</template> </template>
@ -18,6 +19,11 @@
import UiButton from '@/components/UiButton.vue' import UiButton from '@/components/UiButton.vue'
export default { export default {
components: { UiButton }, components: { UiButton },
data(){
return {
orderId : this.$Route.query.orderId
}
}
} }
</script> </script>

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-04-28 15:01:41 * @Date: 2022-04-28 15:01:41
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-06 10:49:00 * @LastEditTime: 2022-07-13 18:41:57
* @Description: file content * @Description: file content
--> -->
@ -55,10 +55,10 @@ export default {
this.reuqestNum++; this.reuqestNum++;
const {error, result} = await ApiGetOrderPaySatus({orderId : this.$Route.query.orderId}); const {error, result} = await ApiGetOrderPaySatus({orderId : this.$Route.query.orderId});
if(error){ if(error){
uin.$u.toast(error.message); uni.$u.toast(error.message);
return false return false
} }
if(!result.isSuccess && this.reuqestNum < 5){ if(!result.isSuccess && this.reuqestNum < 10){
setTimeout(()=>{ setTimeout(()=>{
this.getOrderInfo(); this.getOrderInfo();
}, 1000) }, 1000)
@ -69,9 +69,11 @@ export default {
}, },
back(){ back(){
const payType = this.$Route.query.payType; const payType = this.$Route.query.payType;
if(payType !== 'wxjsapi'){ if(payType === 'wxjsapi'){
this.$Router.back(2); this.$Router.back();
}else{ }else if(payType === 'h5'){
history.back(2);
}else if(payType === 'appWx'){
this.$Router.back(); this.$Router.back();
} }
} }

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-31 14:26:09 * @Date: 2022-03-31 14:26:09
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-04-29 23:06:54 * @LastEditTime: 2022-05-30 17:47:54
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -29,12 +29,12 @@ import UiPageHeader from '@/components/UiPageHeader.vue'
import UiGoodsInfo from '@/components/UiGoodsInfo.vue' import UiGoodsInfo from '@/components/UiGoodsInfo.vue'
import UiWhiteBox from '@/components/UiWhiteBox.vue' import UiWhiteBox from '@/components/UiWhiteBox.vue'
import UiButton from '@/components/UiButton.vue' import UiButton from '@/components/UiButton.vue'
import StatusTips from './components/StatusTips.vue' import StatusTips from './modules/StatusTips.vue'
import UiCell from '@/components/UiCell.vue' import UiCell from '@/components/UiCell.vue'
import GoodsInfo from './components/GoodsInfo.vue' import GoodsInfo from './modules/GoodsInfo.vue'
import AwaitExamine from './components/AwaitExamine.vue' import AwaitExamine from './modules/AwaitExamine.vue'
import SubmitLogistics from './components/SubmitLogistics.vue' import SubmitLogistics from './modules/SubmitLogistics.vue'
import LogisticsInfo from './components/LogisticsInfo.vue' import LogisticsInfo from './modules/LogisticsInfo.vue'
export default { export default {
components: { UiPageHeader, UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, UiCell, GoodsInfo, AwaitExamine, SubmitLogistics, LogisticsInfo }, components: { UiPageHeader, UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, UiCell, GoodsInfo, AwaitExamine, SubmitLogistics, LogisticsInfo },
data(){ data(){

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-20 14:14:53 * @Date: 2022-03-20 14:14:53
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-26 16:33:14 * @LastEditTime: 2022-07-13 18:18:18
* @Description: file content * @Description: file content
--> -->
<template> <template>
@ -34,21 +34,6 @@
maxlength="50" placeholder="填写您想要备注的信息50字以内" /> maxlength="50" placeholder="填写您想要备注的信息50字以内" />
</UiCell> </UiCell>
</UiWhiteBox> </UiWhiteBox>
<UiWhiteBox>
<text class="play--title">支付方式</text>
<radio-group>
<u-cell title="微信支付" :border="false" @click="payType = 'wxpay'">
<image class="play--icon" slot="icon" src="@/static/order/wx.png"/>
<radio class="play--radio" slot="right-icon" color="#FF875B"
:checked="payType == 'wxpay'" ></radio>
</u-cell>
<!-- <u-cell title="支付宝支付" :border="false" @click="payType = 'alipay'">
<image class="play--icon" slot="icon" src="@/static/order/zfb.png"/>
<radio class="play--radio" slot="right-icon" color="#FF875B"
:checked="payType == 'alipay'"></radio>
</u-cell> -->
</radio-group>
</UiWhiteBox>
<UiWhiteBox class="amount"> <UiWhiteBox class="amount">
<u-cell title="商品总额" :value="`¥${orderInfo.productAmount}`" :border="false"></u-cell> <u-cell title="商品总额" :value="`¥${orderInfo.productAmount}`" :border="false"></u-cell>
@ -71,11 +56,13 @@
import {GOODS_TYPE} from '@/common/dicts/goods'; import {GOODS_TYPE} from '@/common/dicts/goods';
import UiCell from '@/components/UiCell'; import UiCell from '@/components/UiCell';
import {ApiPostSubmitOrder, ApiGetBeforeOrder, ApiGetBeforeCartOrder} from '@/common/api/order'; import {ApiPostSubmitOrder, ApiGetBeforeOrder, ApiGetBeforeCartOrder} from '@/common/api/order';
import {ApiPostCashierPrepay} from '@/common/api/pay';
import {ApiGetAddress } from '@/common/api/base'; import {ApiGetAddress } from '@/common/api/base';
import {Wxpay} from '@/common/utils'; import {Wxpay, Alipay} from '@/common/utils';
import UiButton from '@/components/UiButton.vue'; import UiButton from '@/components/UiButton.vue';
import UiWhiteBox from '../../components/UiWhiteBox.vue'; import UiWhiteBox from '../../components/UiWhiteBox.vue';
import UiGoodsInfo from '../../components/UiGoodsInfo.vue'; import UiGoodsInfo from '../../components/UiGoodsInfo.vue';
const ENV = process.env;
export default { export default {
components : {UiCell, UiButton, UiWhiteBox, UiGoodsInfo }, components : {UiCell, UiButton, UiWhiteBox, UiGoodsInfo },
data(){ data(){
@ -84,7 +71,6 @@ export default {
address : {}, address : {},
userMessage : '', userMessage : '',
orderInfo : {}, orderInfo : {},
payType : 'wxpay',
productType : this.$Route.query.productType, productType : this.$Route.query.productType,
} }
}, },
@ -189,11 +175,28 @@ export default {
uni.$u.toast(error.message); uni.$u.toast(error.message);
return false; return false;
} }
if(this.payType === 'wxpay'){ let payType = 'wxjsapi'
Wxpay({orderId : result.orderId, openId : this.$store.state.openId}); if(!this.$store.state.openId){
}else{ payType = 'h5'
uni.$u.toast('暂不支持支付宝支付'); }
const {error:er, result:res} = await ApiPostCashierPrepay({
orderId:result.orderId,
returnUrl : `${ENV.VUE_APP_STATIC_URL}/payResult?orderId=${result.orderId}&payType=${payType}`
});
if(er){
uni.$u.toast(er.message);
return false;
} }
// #ifdef H5
window.location.replace(res.wapCashierUrl)
// #endif
// #ifndef H5
this.$Router.push(`/webView?url=${encodeURIComponent(res.wapCashierUrl)}`);
// #endif
} }
} }
} }

@ -2,7 +2,7 @@
* @Author: ch * @Author: ch
* @Date: 2022-03-21 18:08:07 * @Date: 2022-03-21 18:08:07
* @LastEditors: ch * @LastEditors: ch
* @LastEditTime: 2022-05-05 10:52:27 * @LastEditTime: 2022-06-13 14:25:12
* @Description: file content * @Description: file content
--> -->
<template> <template>

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

Loading…
Cancel
Save