Compare commits

...

125 Commits

Author SHA1 Message Date
msb_39367 550ea9ddf9 feature: 添加打包资源
2 days 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/
dist/
.history/
.hbuilderx/
env.js
yarn.lock

@ -5,18 +5,28 @@
* @LastEditTime: 2022-05-23 21:18:34
* @Description: file content
-->
# shopping-app
严选移动端
## 前置环境
由于项目依赖问题,开发 `node` 版本必须是 `14` or `16`
如果想安装多个版本,可以通过使用 `nvm` 进行版本管理。然具体安装可以参考下面教程
[window install nvm](https://juejin.cn/post/7074108351524634655)
[mac install nvm](https://juejin.cn/post/7206882855200047161)
## 公共方法utils
- 公共方法统一放置utils文件夹内可以按分类建方法文件 如验证类verify.js 请求类request.js
## 公共方法 utils
- 公共方法统一放置 utils 文件夹内,可以按分类建方法文件 如:验证类 verify.js 请求类 request.js
- 所有公共方法采用大驼峰命名法
- 所有的方法都从index.js输出引入时统一引入index不允许直接引入方法文件
- 所有的方法都从 index.js 输出,引入时统一引入 index不允许直接引入方法文件
- 所有方法文件如果导出的是多个方法,不允许在定义方法时导出,必须在文件底部一一导出,并附上方法简单的注释
``` js
```js
// 正确
import {Req, IsPhone} from '@/common/utils';
@ -39,17 +49,20 @@ export const IsPhone = (str) => {....}
export const IsEmail = (str) => {....}
```
## 组件
- 请务必使用easycom模式引入第三方组件
- 根目录的components 只放置真正的组件某个页面的业务模块应该在pages的相应目录下新建components目录放置
- 所有的自定义组件文件名以大驼峰命名且在templet中使用也用大驼峰形式使用
- 请务必使用 easycom 模式引入第三方组件
- 根目录的 components 只放置真正的组件,某个页面的业务模块应该在 pages 的相应目录下新建 components 目录放置
- 所有的自定义组件文件名以大驼峰命名,且在 templet 中使用也用大驼峰形式使用
## 请求
- 所有请求方法命名以Api+请求类型+具体方) 法命名
- 所有请求使用ToAsyncAwait 包裹
- 不允许使用try catch 和 then 处理返回结果
``` js
- 所有请求使用 ToAsyncAwait 包裹
- 不允许使用 try catch 和 then 处理返回结果
```js
// 使用示例
// xxapi.js
import {ToAsyncAwait, ReqestTk} from '@/common/utils'
@ -60,7 +73,7 @@ export const IsEmail = (str) => {....}
}
// user.vue
improt {ApiGetUserInfo} from '@/common/api/xxapi.js';
const getUserInfo = async () =>{
const {error, result} = await ApiGetUserInfo();
if(error){
@ -71,6 +84,8 @@ export const IsEmail = (str) => {....}
}
```
## 图片
- 按pages目录结果放置图片
- 有公共使用的图片请放到static/common文件夹内
- 按 pages 目录结果放置图片
- 有公共使用的图片请放到 static/common 文件夹内

@ -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",
"private": true,
"scripts": {
"serve": "node env.config.js & npm run dev:h5",
"serve:bate": "node env.config.js --ENV:beta & npm run dev:h5",
"serve:prod": "node env.config.js --ENV:prod & npm run dev:h5",
"build": "npm run build:h5",
"server": "npm run dev:h5",
"server:test": "npm run dev:h5-test",
"server:bate": "npm run dev:h5-bate",
"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: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:bate": "node env.config.js --ENV:beta & cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
"build:h5:prod": "node env.config.js --ENV:prod & 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": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode bate",
"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-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",
@ -29,6 +32,9 @@
"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: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-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",
@ -71,35 +77,36 @@
"@dcloudio/uni-quickapp-webview": "^2.0.1-34720220422002",
"@dcloudio/uni-stat": "^2.0.1-34720220422002",
"@vue/shared": "^3.0.0",
"caniuse-lite": "^1.0.30001640",
"core-js": "^3.6.5",
"flyio": "^0.6.2",
"regenerator-runtime": "^0.12.1",
"vue": "^2.6.11",
"vuex": "^3.2.0",
"js-util-all": "^1.0.6",
"mp-html": "^2.2.2",
"regenerator-runtime": "^0.12.1",
"uni-read-pages": "^1.0.5",
"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": {
"@babel/runtime": "~7.12.0",
"@dcloudio/types": "^2.6.7",
"@dcloudio/uni-automator": "^2.0.1-34720220422002",
"@dcloudio/uni-cli-i18n": "^2.0.1-34720220422002",
"@dcloudio/uni-cli-shared": "^2.0.1-34720220422002",
"@dcloudio/uni-migration": "^2.0.1-34720220422002",
"@dcloudio/uni-template-compiler": "^2.0.1-34720220422002",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.1-34720220422002",
"@dcloudio/vue-cli-plugin-uni": "^2.0.1-34720220422002",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.1-34720220422002",
"@dcloudio/webpack-uni-mp-loader": "^2.0.1-34720220422002",
"@dcloudio/webpack-uni-pages-loader": "^2.0.1-34720220422002",
"@dcloudio/uni-automator": "2.0.2-4010520240507001",
"@dcloudio/uni-cli-i18n": "2.0.2-4010520240507001",
"@dcloudio/uni-cli-shared": "2.0.2-4010520240507001",
"@dcloudio/uni-migration": "2.0.2-4010520240507001",
"@dcloudio/uni-template-compiler": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-hbuilderx": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-uni": "2.0.2-4010520240507001",
"@dcloudio/vue-cli-plugin-uni-optimize": "2.0.2-4010520240507001",
"@dcloudio/webpack-uni-mp-loader": "2.0.2-4010520240507001",
"@dcloudio/webpack-uni-pages-loader": "2.0.2-4010520240507001",
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"babel-plugin-import": "^1.11.0",
"cross-env": "^7.0.2",
"jest": "^25.4.0",
"babel-plugin-import": "1.13.8",
"cross-env": "7.0.3",
"jest": "25.5.4",
"mini-types": "*",
"miniprogram-api-typings": "*",
"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>
<html lang="zh-CN">
@ -14,7 +21,7 @@
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<body class="page">
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</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
* @Date: 2022-04-06 17:29:13
* @LastEditors: ch
* @LastEditTime: 2022-04-15 14:17:14
* @LastEditTime: 2022-05-31 11:18:44
* @Description: file content
*/
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
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
// * @Date: 2022-05-18 15:21:10
// * @LastEditors: ch
// * @LastEditTime: 2022-05-18 17:24:37
// * @Description: file content
// */
// import { MsbSkt } from "../utils/webSkt";
// import { CreateUUID } from '@/common/utils';
/*
* @Author: ch
* @Date: 2022-05-27 17:44:36
* @LastEditors: ch
* @LastEditTime: 2022-06-09 11:34:36
* @Description: file content
*/
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/im';
// /**
// * 系统消息心跳
// */
// export const ApiSktSysHeart = () => MsbSkt.send({
// traceId: CreateUUID(),
// 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
// });
/**
* 获取soket登录秘钥
*/
export const ApiGetSoketTicket = () => ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/ticket`, {
ticketType: 'CONNECT_TICKET'
}));

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-29 17:38:17
* @LastEditors: ch
* @LastEditTime: 2022-05-10 16:14:53
* @LastEditTime: 2022-06-23 16:21:32
* @Description: file content
*/
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
@ -84,8 +84,11 @@ export const ApiPutCancelOrder = (data) =>
export const ApiGetOrderStatistics = () =>
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
* @Date: 2022-04-28 16:30:54
* @LastEditors: ch
* @LastEditTime: 2022-05-17 20:07:26
* @LastEditTime: 2022-06-29 17:16:50
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/trade';
// 第三方鉴权服务
const AUTH_URL = '/third';
const APPID = 'wxd2015f0c56defa02';
@ -33,24 +32,3 @@ export const ApiGetOpenId = ({code}) =>
*/
export const ApiPostThirdInfo = (data) =>
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
* @Date: 2022-05-26 11:49:16
* @LastEditors: ch
* @LastEditTime: 2022-05-26 17:00:06
* @LastEditTime: 2022-06-22 11:23:02
* @Description: file content
*/
@ -11,13 +11,25 @@ export const ORDER_STATUS = {
// 待支付
AWAIT_PAY: 1
}
export const ORDER_TYPE = {
//(1, "普通订单"),
NORMAL: 1,
//(2, "免费订单"),
FREE: 2,
//(3, "秒杀订单"),
SECKILL: 3,
//(4, "虚拟商品订单"),
VIRTUAL : 4
export default {
TYPE : {
//(1, "普通订单"),
NORMAL: 1,
//(2, "免费订单"),
FREE: 2,
//(3, "秒杀订单"),
SECKILL: 3,
//(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,362 +2,482 @@
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-05-24 22:51:47
* @LastEditTime: 2022-06-14 17:24:14
* @Description: file content
*/
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
const connect = Symbol('connect'),
send = Symbol('send'),
onResponse = Symbol('onResponse'),
onMessage = Symbol('onMessage'),
updateData = Symbol('updateData')
;
export default class MsbIm {
option = {
ioKey : 'traceId',
reconnect: true,
logout : false
}
socket = null;
queue = {};
interceptors = {
dataChangeBefore: null,
dataChangeAfter: null,
onLogout : null,
onMessage: null
};
sessionData = [];
curSessionId = null;
constructor(option) {
this.option = {
...this.option,
...option
}
}
/**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option
*/
[connect](option) {
return new Promise((resolve, reject) => {
this.socket = uni.connectSocket({
...option,
fail(e){
reject(e);
}
});
this.socket.onOpen(() => {
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[onMessage](result);
// 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]];
if (cbk) {
cbk(result.code !== 200 ? {error:result} : {result:result});
delete this.queue[result[this.option.ioKey]];
}
})
resolve(this.socket);
});
this.socket.onClose(() => {
if (this.option.reconnect && !this.option.logout) {
this[connect]();
}
this.option.logout = false;
});
});
}
/**
* 向服务端发送消息||请求返回一个Promise对象收到ioKey对应的消息会算一个同步完成
* @param {*} data
*/
[send](data) {
return new Promise((resolve, reject) => {
this.queue[data[this.option.ioKey]] = ({result, error}) => {
if (result) {
resolve(result);
} else {
reject(error);
}
};
this.socket.send({
data : JSON.stringify(data),
fail(e) {
reject({error : e});
}
});
})
}
/**
* 服务端推送消息只处理服务端主动推送的消息
* @param {*} data
*/
[onMessage](data) {
// 判断非服务端主动推送消息不做处理
if (data[this.option.ioKey] || data.code !== 200) {
return false;
}
let ctx = data.content;
let historyData = [...this.sessionData],
newData = [];
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId);
if(hisIndex >= 0){
// 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息
const curHisData = historyData[hisIndex];
curHisData.messageList.push(ctx);
curHisData.lastMessage = ctx;
// 不在当前会话窗口则向会话消息加1条未读
if(ctx.sessionId !== this.curSessionId){
curHisData.unreadCount++;
}
newData = historyData;
}else{
// 会话列表不存在,则创建一个会话
newData = [...historyData, {
fromAvatar : ctx.fromAvatar,
fromId : ctx.fromId,
fromNickname : ctx.fromNickname,
id : ctx.id,
lastMessage : ctx,
messageList : [ctx],
unreadCount : 1
}]
}
this.setSessionData(newData)
}
init (config) {
return new Promise((resolve, reject) => {
const heart = () => {
setTimeout(async () => {
await this[send]({
traceId: CreateUUID(),
traceType: '0',
content: { text: "ping" }
}).catch((e)=>{});
heart();
},5000)
}
this[connect]({
...config,
}).then(() => {
heart();
resolve(this);
}).catch((e)=>{});
})
}
logout() {
this.option.logout = true;
this.socket.close();
this.interceptors.onLogout && this.interceptors.onLogout();
}
/**
* 设置数据
*/
setSessionData(data) {
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(data, this.sessionData);
this.sessionData = data;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}
/**
* 设置当前聊天窗口
* Data为Session数据
* @param {*} data
*/
setCurSessionId(id) {
this.curSessionId = id;
}
/**
* 获取会话列表
* @param {*} params
*/
async getSessionList(params) {
let {error, result} = await ToAsyncAwait(this[send]({
traceId: CreateUUID(),
traceType : 1,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
content.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = this.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id);
if(hisIndex >= 0){
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
this.setSessionData(historyData)
}else{
item.messageList = [];
const newData = [...historyData, item]
this.setSessionData(newData);
}
});
return Promise.resolve(result);
}
/**
* 获取会话的历史消息记录
* @param {*} params
*/
async getHistoryMsg(params) {
const {error, result} = await ToAsyncAwait(this[send]({
traceId: CreateUUID(),
traceType: 23,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
if (content.length) {
let newData = this.sessionData;
const hisIdx = newData.findIndex(i => i.id === content[0].sessionId);
content.forEach(item => {
item.payload = JSON.parse(item.payload)
})
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(content);
this.setSessionData(newData);
}
return Promise.resolve(result);
}
/**
* 会话已读
* @param {*} params
*/
async setRead (params){
await this[send]({
traceId : CreateUUID(),
traceType : "6",
...params
});
let newData = this.sessionData.map(item => {
if (item.id == params.content.sessionId) {
item.unreadCount = 0;
}
return item;
});
this.setSessionData(newData);
}
/**
* 发送消息
* @param {*} params
*/
async sendMsg(params) {
const index = this.sessionData.findIndex(i => i.id === this.curSessionId)
let curSession = this.sessionData[index];
// 临时消息体
let par = {
...params,
traceId: CreateUUID(),
traceType: 20,
}
let msgCtx = {
...params.content,
...par,
fromId: params.fromId,
createTimeStamp : (new Date()).getTime(),
sendStatus : 'loading'
}
// 点发送,立即把消息加入消息列表,标记为发送中状态
curSession.messageList.push(msgCtx);
// 超过时间未返回视为发送失败
this.timerStatus(msgCtx);
const { error, result } = await ToAsyncAwait(this[send](par));
// 接到通知,标记消息是否发送成功
for (let i = curSession.messageList.length; i--;) {
const item = curSession.messageList[i];
if (item[this.option.ioKey] === par[this.option.ioKey]) {
curSession.messageList[i].sendStatus = msgCtx.sendStatus = error ? 'fail' : 'success';
break;
}
}
let newData = [...this.sessionData];
newData[index] = curSession;
this.setSessionData(newData);
if (error) {
return Promise.reject(error);
}
import './potoReq';
import './protoRsp'
const connect = Symbol('connect');
const send = Symbol('send');
const onMessage = Symbol('onMessage');
const fromatPotoReq = (traceId, traceType, content) => {
let messageModel = new proto.ReqModel();
messageModel.setTraceid(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(),
};
};
return Promise.resolve(result);
}
/**
* 发送失败时重新发送
* @param {*} params
*/
async resend(params) {
params.sendStatus = 'loading';
this.timerStatus(params)
const { error, result } = await ToAsyncAwait(this[send]({
traceId: params.traceId,
traceType: params.traceType,
content : params.content
}));
params.createTimeStamp = result.createTimeStamp;
if (error) {
params.sendStatus = 'fail';
return Promise.reject(error);
}
params.sendStatus = 'success';
return Promise.resolve(result);
}
timerStatus(msg) {
setTimeout(() => {
if (msg.sendStatus === 'loading') {
msg.sendStatus = 'fail';
delete this.queue[msg.traceId];
}
}, 3000);
}
/**
* 主动创建会话
* @param {*} params
*/
async createSession (params){
const { result, error } = await ToAsyncAwait(this[send]({
traceId : CreateUUID(),
traceType : 21,
...params
}));
if (error) {
return Promise.reject(error);
}
const { content } = result;
let historyData = this.sessionData;
let curSession = historyData.find(i => i.id === content.id);
if (!curSession) {
curSession = {
...content,
unreadCount: 0,
messageList : []
}
const newData = [...historyData, curSession];
this.setSessionData(newData);
}
return Promise.resolve(result);
}
}
class MsbIm {
defaultOption = {
ioKey: 'traceId',
reconnect: true,
};
socket = null;
isOpen = false;
queue = {};
interceptors = {
dataChangeBefore: null,
dataChangeAfter: null,
onClose: null,
onMessage: null,
};
sessionData = [];
curSessionId = null;
constructor(option) {
this.option = {
...this.defaultOption,
...option,
};
}
/**
* 创建连接返回一个Promise 创建成功并成功打开连接算连接成功
* @param {*} option
*/
[connect](option) {
return new Promise((resolve, reject) => {
const open = () => {
console.log('[im] open');
this.isOpen = true;
resolve(this.socket);
};
const message = async (res) => {
const result = fromatPotoRsp(res.data);
this.interceptors.onMessage && this.interceptors.onMessage(result);
// 处理服务端主动推送的消息
this[onMessage](result);
// 如果再消息堆里有此消息回调,则执行回调,并删除
const cbk = this.queue[result[this.option.ioKey]];
if (cbk) {
cbk(result.code !== 200 ? { error: result } : { result: result });
delete this.queue[result[this.option.ioKey]];
}
};
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(() => {
close();
});
} 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);
}
}
});
}
/**
* 向服务端发送消息||请求返回一个Promise对象收到ioKey对应的消息会算一个同步完成
* @param {*} data
*/
[send](data) {
return new Promise((resolve, reject) => {
if (!this.isOpen) {
return reject('连接未打开');
}
this.queue[data[this.option.ioKey]] = ({ result, error }) => {
if (result) {
resolve(result);
} else {
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({
data: par,
fail(e) {
reject({ error: e });
},
});
} else if (WebSocket) {
this.socket.send(par);
}
});
}
/**
* 服务端推送消息只处理服务端主动推送的消息
* @param {*} data
*/
[onMessage](data) {
// 判断非服务端主动推送消息不做处理
if (data[this.option.ioKey] || data.code !== 200) {
return false;
}
console.log('[im] 主动接收的消息', data);
let ctx = data.content;
let historyData = [...this.sessionData],
newData = [];
const hisIndex = historyData.findIndex((i) => i.id === ctx.sessionId);
if (hisIndex >= 0) {
// 存在会话往现有会话增加一条消息,并修改最后一条消息为当前消息
const curHisData = historyData[hisIndex];
curHisData.messageList.push(ctx);
curHisData.lastMessage = ctx;
// 不在当前会话窗口则向会话消息加1条未读
if (ctx.sessionId !== this.curSessionId) {
curHisData.unreadCount++;
} else {
this.setRead({
content: {
sessionId: this.curSessionId,
},
});
}
newData = historyData;
} else {
// 会话列表不存在,则创建一个会话
newData = [
...historyData,
{
fromAvatar: ctx.session.fromAvatar,
fromId: ctx.session.fromId,
fromNickname: ctx.session.fromNickname,
id: ctx.sessionId,
lastMessage: ctx,
messageList: [ctx],
updateTimeStamp: ctx.createTimeStamp,
unreadCount: 1,
},
];
}
this.setSessionData(newData);
}
init(config) {
return new Promise((resolve, reject) => {
const heart = () => {
// 要优化 心跳没回复需要重连
setTimeout(async () => {
if (this.isOpen) {
await this[send]({
traceId: CreateUUID(),
traceType: 0,
content: { text: 'ping' },
});
}
heart();
}, 1000);
};
this.option = {
...this.option,
...config,
};
this[connect]()
.then((res) => {
resolve(res);
heart();
})
.catch((e) => {
console.log('eeeee', e);
});
});
}
/**
* 设置数据
*/
setSessionData(data) {
let newData = JSON.parse(JSON.stringify(data));
this.interceptors.dataChangeBefore && this.interceptors.dataChangeBefore(newData, this.sessionData);
this.sessionData = newData;
this.interceptors.dataChangeAfter && this.interceptors.dataChangeAfter(this.sessionData);
}
/**
* 设置当前聊天窗口
* Data为Session数据
* @param {*} data
*/
setCurSessionId(id) {
this.curSessionId = id;
}
/**
* 获取会话列表
* @param {*} params
*/
async getSessionList(params) {
const par = {
traceId: CreateUUID(),
traceType: 1,
...params,
};
console.log('[im] 获取会话列表--start', par);
let { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 获取会话列表--end', result, error);
if (error) {
return Promise.reject(error);
}
const { content } = result;
// let newData = [];
content.sessionVOS.forEach((item) => {
if (item.lastMessage) {
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = this.sessionData;
let hisIndex = historyData.findIndex((i) => i.id === item.id);
if (hisIndex < 0) {
item.messageList = [];
}
// 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);
}
/**
* 获取会话的历史消息记录
* @param {*} params
*/
async getHistoryMsg() {
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(),
traceType: 2,
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) {
return Promise.reject(error);
}
const { content } = result;
if (content.length) {
let newData = this.sessionData;
content.forEach((item) => {
item.payload = JSON.parse(item.payload);
});
newData[curSessionIdx].messageList = content.concat(newData[curSessionIdx].messageList);
this.setSessionData(newData);
}
return Promise.resolve(result);
}
/**
* 会话已读
* @param {*} params
*/
async setRead(params) {
const par = {
traceId: CreateUUID(),
traceType: '6',
...params,
};
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) {
item.unreadCount = 0;
}
return item;
});
this.setSessionData(newData);
}
/**
* 发送消息
* @param {*} params
*/
async sendMsg(params) {
const index = this.sessionData.findIndex((i) => i.id === this.curSessionId);
let curSession = this.sessionData[index];
// 临时消息体
let par = {
...params,
traceId: CreateUUID(),
traceType: 3,
};
let msgCtx = {
...params.content,
...par,
createTimeStamp: new Date().getTime(),
sendStatus: 'loading',
};
if (typeof msgCtx.payload === 'string') {
msgCtx.payload = JSON.parse(msgCtx.payload);
}
// 点发送,立即把消息加入消息列表,标记为发送中状态
curSession.lastMessage = msgCtx;
curSession.messageList.push(msgCtx);
this.setSessionData(this.sessionData);
// 超过时间未返回视为发送失败
this.timerStatus(msgCtx);
console.log('[im] 发送消息--start', par);
const { error, result } = await ToAsyncAwait(this[send](par));
console.log('[im] 发送消息--end', result, error);
// 接到通知,标记消息是否发送成功
for (let i = curSession.messageList.length; i--; ) {
const item = curSession.messageList[i];
if (item[this.option.ioKey] === par[this.option.ioKey]) {
curSession.messageList[i].sendStatus = msgCtx.sendStatus = error ? 'fail' : 'success';
break;
}
}
let newData = [...this.sessionData];
curSession.lastMessage = msgCtx;
newData[index] = curSession;
this.setSessionData(newData);
if (error) {
return Promise.reject(error);
}
return Promise.resolve(result);
}
/**
* 发送失败时重新发送
* @param {*} params
*/
async resend(params) {
params.sendStatus = 'loading';
this.timerStatus(params);
console.log('[im] 重新发送消息--start', params);
const { error, result } = await ToAsyncAwait(
this[send]({
traceId: params.traceId,
traceType: params.traceType,
content: params.content,
})
);
console.log('[im] 重新发送消息--end', result, error);
params.createTimeStamp = result.createTimeStamp;
if (error) {
params.sendStatus = 'fail';
return Promise.reject(error);
}
params.sendStatus = 'success';
return Promise.resolve(result);
}
timerStatus(msg) {
setTimeout(() => {
if (msg.sendStatus === 'loading') {
msg.sendStatus = 'fail';
delete this.queue[msg.traceId];
}
}, 3000);
}
/**
* 主动创建会话
* @param {*} params
*/
async createSession(params) {
const par = {
traceId: CreateUUID(),
traceType: 9,
...params,
};
console.log('[im] 主动创建会话--start', par);
const { result, error } = await ToAsyncAwait(this[send](par));
console.log('[im] 主动创建会话--end', result, error);
if (error) {
return Promise.reject(error);
}
const { content } = result;
let historyData = this.sessionData;
let curSession = historyData.find((i) => i.id === content.id);
if (!curSession) {
curSession = {
...content,
unreadCount: 0,
messageList: [],
};
const newData = [...historyData, curSession];
this.setSessionData(newData);
}
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
* @Date: 2022-03-18 11:11:05
* @LastEditors: ch
* @LastEditTime: 2022-03-18 11:11:05
* @LastEditTime: 2022-07-12 18:31:15
* @Description: file content
*/
import {RouterMount,createRouter} from 'uni-simple-router';
@ -13,6 +13,11 @@ const router = createRouter({
});
//全局路由前置守卫
router.beforeEach((to, from, next) => {
// 兼容页面刷新body样式丢失问题
// console.log(document);
if (document) {
document.body.setAttribute('class', `uni-body ${to.path.replace('/', '').replace(/\//g, '-')}`)
}
next();
});
// 全局路由后置守卫

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 18:28:52
* @LastEditors: ch
* @LastEditTime: 2022-05-21 11:38:51
* @LastEditTime: 2022-06-22 15:31:09
* @Description: file content
*/
import Vue from 'vue'
@ -17,16 +17,22 @@ const
// 地址列表
ADDRESS = 'ads',
// oppenId
OPPED_ID = 'oi';
OPPED_ID = 'oi',
// 每个浏览器创建一个UUID作为同一个用户的标识
UUID = 'uid',
// 评价图片预览数据
COMMENT_PREVIEW = 'comment_preview';
export default new Vuex.Store({
state : {
token : uni.getStorageSync(TOKEN) || '',
userInfo : JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address : JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
state: {
token: uni.getStorageSync(TOKEN) || '',
userInfo: JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address: JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
openId: uni.getStorageSync(OPPED_ID) || '',
uuid: uni.getStorageSync(UUID) || '',
comment_preview: JSON.parse(uni.getStorageSync(COMMENT_PREVIEW) || '{}'),
imData : [],
imMsgCount : 0,
openId : uni.getStorageSync(OPPED_ID) || ''
imMsgCount : 0
},
mutations:{
SET_TOKEN (state, token = ''){
@ -41,15 +47,23 @@ export default new Vuex.Store({
state.address = 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){
state.imData = data ;
},
SET_IM_MSG_COUNT (state, data){
state.imMsgCount = data;
},
SET_OPEN_ID (state, data){
state.openId = data;
uni.setStorageSync(OPPED_ID, data);
}
},
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
* @Date: 2022-05-20 11:00:07
* @LastEditors: ch
* @LastEditTime: 2022-05-23 14:54:50
* @LastEditTime: 2022-07-13 10:37:52
* @Description: file content
*/
import MsbIm from '@/common/plugins/msbIm' ;
import { ToAsyncAwait } from '@/common/utils';
import { ToAsyncAwait, FormatJsonSearch } from '@/common/utils';
import { ApiGetCurrentUser } from '@/common/api/account';
import { ApiGetSoketTicket } from '@/common/api/im';
import $store from '@/common/store';
import ENV from '@/common/config/env';
const ENV = process.env;
const Im = new MsbIm({
reconnect: true,
});
const ImInit = async () => {
const { error } = await ApiGetCurrentUser();
const { error, result } = await ApiGetSoketTicket();
if (error) {
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({
// url: `wss://k8s-horse-gateway.mashibing.cn/ws?client=${$store.state.token}&type=1`
url: `${ENV.imUrl}/ws?client=${$store.state.token}&type=1`
url: `${ENV.VUE_APP_IM_URL}/ws${par}`
}))
};
@ -32,11 +41,10 @@ Im.interceptors.dataChangeAfter = () => {
Im.sessionData.forEach(i => {
msgCount += i.unreadCount;
})
console.log(Im.sessionData)
$store.commit('SET_IM_MSG_COUNT', msgCount);
}
Im.interceptors.onLogout = () => {
Im.interceptors.onClose = () => {
Im.setSessionData([]);
Im.setCurSessionId(null);
$store.commit('SET_IM_DATA', []);

@ -2,17 +2,22 @@
* @Author: ch
* @Date: 2022-03-22 16:52:28
* @LastEditors: ch
* @LastEditTime: 2022-05-20 11:42:33
* @LastEditTime: 2022-06-29 17:28:39
* @LastEditTime: 2022-06-29 17:22:32
* @Description: 所有工具类统一在这输出
*/
import * as util from './utils';
import * as requset from './requset';
import * as im from './im';
import * as wxpay from './wxpay';
import * as uploadFileOss from './uploadFileOss';
import * as alipay from './alipay';
export * from './utils';
export * from './requset';
export * from './im';
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
* @Date: 2022-05-06 15:33:55
* @LastEditors: ch
* @LastEditTime: 2022-05-26 19:04:50
* @LastEditTime: 2022-07-13 10:38:34
* @Description: file content
*/
import { ApiPostWxH5Pay, ApiPostWxJsApiPay } from '@/common/api/wx';
import ENV from '@/common/config/env';
import { Wxpay } from './wxpay';
export const pay = ({orderId, openId, payType})=>{
if(payType === 'wxpay'){
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
* @Date: 2022-03-17 17:42:32
* @LastEditors: ch
* @LastEditTime: 2022-05-23 15:19:36
* @LastEditTime: 2022-07-13 10:39:07
* @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法
*/
import MsbUniRequest from '@/common/plugins/msbUniRequest';
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
@ -75,7 +82,7 @@ const clearRepeat = (option) =>{
// 不需要token的接口封装
const MsbRequest = new MsbUniRequest();
MsbRequest.baseUrl = ENV.baseUrl;
MsbRequest.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequest.use('request', (option) => {
if(option.header.repeat){
@ -85,6 +92,7 @@ MsbRequest.use('request', (option) => {
return isRepeatVerify;
}
}
option.header.uid = uuid;
return option;
})
MsbRequest.use('success', successIntercept);
@ -94,28 +102,29 @@ MsbRequest.use('error', errorIntercept);
// 需要token的接口封装
const MsbRequestTk = new MsbUniRequest();
MsbRequestTk.baseUrl = ENV.baseUrl;
MsbRequestTk.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequestTk.use('request', (option) => {
const token = $store.state.token;
if(!token){
option.header.uid = uuid;
if(!token && !option.header.notVerifyToken){
// 登录状态处理没有token直接跳转至登录
uni.redirectTo({
url: '/login'
});
return Promise.reject({message:'要先登录才能操作哦~'});
}else{
option.header = {...option.header, Authorization:token};
if(option.header.repeat){
// 如果当前请求不允许重复调用,则检查重复请求,当前接口有正在请求则不发起请求
const isRepeatVerify = repeatVerify(option);
if(isRepeatVerify){
return isRepeatVerify;
}
}
delete option.header.notVerifyToken
option.header = {...option.header, Authorization:token};
if(option.header.repeat){
// 如果当前请求不允许重复调用,则检查重复请求,当前接口有正在请求则不发起请求
const isRepeatVerify = repeatVerify(option);
if(isRepeatVerify){
return isRepeatVerify;
}
return option;
}
return option;
})
MsbRequestTk.use('success', successIntercept);
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,18 +2,20 @@
* @Author: ch
* @Date: 2022-03-17 19:15:10
* @LastEditors: ch
* @LastEditTime: 2022-05-23 11:40:29
* @LastEditTime: 2022-07-13 10:39:35
* @Description: 一些无法归类的公共方法容器
*/
import {
toAsyncAwait as ToAsyncAwait,
isPhone as IsPhone,
formatDate as FormatDate,
creatUuid as CreateUUID,
formatSearchJson as FormatSearchJson
toAsyncAwait as ToAsyncAwait,
isPhone as IsPhone,
formatDate as FormatDate,
creatUuid as CreateUUID,
formatSearchJson as FormatSearchJson,
formatJsonSearch as FormatJsonSearch
} from "js-util-all";
import {AD_JUMP_TYPE} from '@/common/dicts/ad';
/**
* 首次运行时把定时器赋值给一个变量 第二次执行时
@ -22,28 +24,76 @@ import {
* 没有执行清除定时器 超过一定时间后触发回调函数
*/
const Debounce = (fn, delay) => {
let timer
return function() {
const that = this
const _args = arguments // 存一下传入的参数
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
fn.apply(that, _args)
}, delay)
}
let timer
return function () {
const that = this
const _args = arguments // 存一下传入的参数
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
fn.apply(that, _args)
}, 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 {
// async await 标识结果处理
ToAsyncAwait,
// 判断是否为手机号
IsPhone,
// 时间格式化
FormatDate,
FormatSearchJson,
CreateUUID,
// 防抖函数
Debounce
// async await 标识结果处理
ToAsyncAwait,
// 判断是否为手机号
IsPhone,
// 时间格式化
FormatDate,
FormatSearchJson,
FormatJsonSearch,
CreateUUID,
// 防抖函数
Debounce,
// 广告跳转
AdJump,
HandleApiError
}

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-20 16:45:27
* @LastEditors: ch
* @LastEditTime: 2022-05-06 14:26:57
* @LastEditTime: 2022-06-22 19:34:13
* @Description: file content
-->
<template>
@ -38,10 +38,10 @@ export default {
...this.params
});
const res = result.records.map(item => {
// item.labelList[{text:'x',code : 'recommended'},{text:'x',code : 'second_kill'}]
//
item.seckill = false;
item.tagList = [];
item.labelList = item.labelList || [];
item.labelList.forEach(i => {
if(i.code === 'second_kill'){
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
* @Date: 2022-04-19 11:37:50
* @LastEditors: ch
* @LastEditTime: 2022-05-05 11:08:44
* @LastEditTime: 2022-06-29 17:27:12
* @Description: file content
-->
<template>
@ -12,7 +12,7 @@
<script>
import UiRadioPicker from './UiRadioPicker.vue'
import { ApiPostWxPay } from '@/common/api/order';
import { Wxpay } from '@/common/utils';
import { Wxpay, Alipay } from '@/common/utils';
export default {
components: { UiRadioPicker },
props : {
@ -32,13 +32,19 @@ export default {
label : '微信支付',
value : 'wxpay'
},
// {
// label : '',
// value : 'alipay'
// }
]
}
},
mounted(){
// APP
if(!this.$store.state.openId){
this.options.push({
label : '支付宝支付',
value : 'alipay'
})
}
},
methods:{
confirm(val){
const orderId = this.order.orderId;
@ -46,7 +52,8 @@ export default {
Wxpay({orderId, openId: this.$store.state.openId});
this.close();
}else{
uni.$u.toast('暂不支持支付宝支付');
// uni.$u.toast('');
Alipay({orderId})
}
},
close(){

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2021-07-26 23:22:16
* @LastEditors: ch
* @LastEditTime: 2022-05-23 20:55:47
* @LastEditTime: 2022-06-20 17:38:48
* @Description: file content
*/
import Vue from 'vue';
@ -13,19 +13,40 @@ import uView from 'uview-ui';
import store from '@/common/store';
import {FormatSearchJson} from '@/common/utils';
import {ApiGetOpenId, ApiGetAuthUrl} from '@/common/api/wx';
import {ApiGetCurrentUser} from '@/common/api/account';
import {Im, ImInit} from '@/common/utils';
import { ApiSktSysGetSession, ApiSktSysHeart } from './common/api/im';
if (store.state.token) {
const socketInit = () => {
if (!store.state.userInfo.id) {
setTimeout(() => {
socketInit();
},10000)
return false;
}
// 初始化IM
ImInit().then(() => {
// 获取到会话列表
Im.getSessionList({
content: { sysId : 1 }
});
Im.getSessionList();
});
}
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() : '';

@ -1,6 +1,6 @@
{
"name" : "马士兵严选",
"appid" : "__UNI__3FB31B6",
"appid" : "__UNI__5FEB250",
"description" : "",
"versionName" : "1.0.1",
"versionCode" : "100",
@ -40,10 +40,14 @@
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
"minSdkVersion" : 21
},
/* ios */
"ios" : {},
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {},
@ -52,39 +56,18 @@
"__platform__" : [ "android" ],
"appid" : "wx17b34a4a90ef18f7",
"UniversalLinks" : ""
},
"alipay" : {
"__platform__" : [ "android" ]
}
}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.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"
}
"hdpi" : "src/static/app-icon/72.png",
"xhdpi" : "src/static/app-icon/96.png",
"xxhdpi" : "src/static/app-icon/144.png",
"xxxhdpi" : "src/static/app-icon/192.png"
}
}
}
@ -118,20 +101,7 @@
"base" : ""
},
"devServer" : {
"proxy" : {
"/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"
}
}
"port" : 8080
},
"optimization" : {
"treeShaking" : {

@ -1,75 +0,0 @@
{
"name": "",
"appid": "",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
"app-plus": { /* 5+App */
"usingComponents": true,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
},
"modules": { /* */
},
"distribute": { /* */
"android": { /* android */
"permissions": ["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
"ios": { /* ios */
},
"sdkConfigs": { /* SDK */
}
}
},
"quickapp": { /* */
},
"mp-weixin": { /* */
"appid": "",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"mp-qq" : {
"usingComponents" : true
}
}

@ -10,6 +10,13 @@
"backgroundColor" : "#69ADE5"
}
},
{
"path": "pages/webView",
"aliasPath" : "/webView",
"style": {
"navigationBarTitleText": "收银台"
}
},
{
"path": "pages/login",
"aliasPath" : "/login",
@ -58,6 +65,42 @@
"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",
"aliasPath" : "/account",
@ -177,6 +220,20 @@
"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",
"aliasPath" : "/saleAfterList",

@ -3,7 +3,7 @@
components: { UiCell },: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:07
* @LastEditTime: 2022-06-28 16:38:33
* @Description: file content
-->
<template>
@ -38,6 +38,11 @@
<image class="item-icon" src="@/static/account/sh.png"/>
<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 class="cell">
@ -135,6 +140,10 @@ page {
top: 10rpx;
z-index: 99;
border: 1px solid #fff;
/* #ifndef H5 */
top: 90rpx;
/* #endif */
}
&--cell{
border: 0;

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

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

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

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

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

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

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

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

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

@ -17,10 +17,11 @@
<!-- 右侧 二级分类 -->
<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 class="cate-tow-group" :class="idx === categoryData[curIndex].children.length - 1 ? 'cate-tow-group__last' :''"
v-for="(item, idx) in categoryData[curIndex].children" :key="idx">
<view class="cate-tow-group" :class="idx === curTwoCategory.children.length - 1 ? 'cate-tow-group__last' :''"
v-for="(item, idx) in curTwoCategory.children" :key="idx">
<text class="cate-tow-group--title">{{item.name}}</text>
<view class="cate-tow-group--item" v-for="i in item.productList" :key="i.id"
@click="$Router.push(`/goodsDetail?id=${i.id}`)">
@ -30,9 +31,9 @@
</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')" />
<u-loadmore status="loading" v-if="categoryData[curIndex].isLoading" />
<u-loadmore status="loading" v-if="curTwoCategory.isLoading" />
</scroll-view>
</view>
<BsEmpty v-if="!categoryData.length && !isLoading" />
@ -45,6 +46,9 @@
import {ApiGetCategoryOneList, ApiGetCategoryTwoAndGoods} from '@/common/api/goods';
import BsEmpty from "@/components/BsEmpty";
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 {
components: { BsEmpty, UiPageHeader },
data() {
@ -59,6 +63,11 @@ export default {
isLoading: true,
};
},
computed:{
curTwoCategory(){
return this.categoryData[this.curIndex];
}
},
onLoad() {
//
this.getCategoryData();
@ -94,11 +103,12 @@ export default {
item.children = [];
item.isLoading = true;
this.getTwoCategoryData(item);
this.getTwoCategoryAd(item);
return item;
});
this.isLoading = false;
},
/**
* 初始化分类列表数据
* @param {Object} result
@ -107,6 +117,24 @@ export default {
const {error, result} = await ApiGetCategoryTwoAndGoods({categoryId : item.id});
this.$set(item, 'children', result);
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
* @Date: 2022-03-23 17:27:21
* @LastEditors: ch
* @LastEditTime: 2022-05-19 11:24:09
* @LastEditTime: 2022-07-04 16:26:33
* @Description: file content
-->
<template>
@ -22,14 +22,16 @@
</view>
<view class="goods-info--title">{{goods.name}}</view>
</view>
<view class="select">
<view class="box">
<Service></Service>
<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"
:goodsInfo="goods" :skuInfo="skuInfoData" :activityStatus="activityStatus">
</SkuPopup>
</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"/>
</view>
<view class="footer--not-stock" v-if="stock === 0">~</view>
@ -47,20 +49,23 @@
</template>
<script>
import {FormatDate} from '@/common/utils';
import {FormatDate, HandleApiError} from '@/common/utils';
import {ApiGetGoodsDetail, ApiGetGoodsSkus} from '@/common/api/goods';
import SlideImage from './components/SlideImage.vue';
import Service from './components/Service.vue';
import SkuPopup from './components/SkuPopup.vue';
import {ApiGetCommentList, ApiGetCommentCount} from '@/common/api/comment';
import SlideImage from './modules/SlideImage.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 UiButton from '../../../components/UiButton.vue';
import SeckillPrice from './components/SeckillPrice.vue';
import Comment from './modules/Comment.vue';
export default {
components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice},
components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice, Comment},
data(){
return {
// 1
stock : 1,
goodsId : this.$Route.query.id,
goods : {
pictureList : []
},
@ -73,7 +78,10 @@ export default {
sku : '',
num : 1
},
productActivityVO : {}
productActivityVO : {},
commentList : [],
commentCount : 0
}
},
computed:{
@ -96,8 +104,11 @@ export default {
async getGoodsDetail(){
const {query} = this.$Route;
const {error, result} = await ApiGetGoodsDetail({id : query.id});
if(error){
uni.$u.toast(error.message);
if(HandleApiError(error, 'getGoodsDetail')){
return false;
}
if(!result.isEnable){
this.$Router.replace('/enable')
return false;
}
this.goods = {...result,
@ -119,22 +130,42 @@ export default {
originalPrice:result.startingPrice
};
this.getGoodsSkus();
this.getComment();
this.getCommentCount();
},
async getGoodsSkus(){
const {query} = this.$Route;
const {error, result} = await ApiGetGoodsSkus({productId : query.id});
if(error) {
uni.$u.toast(error.message);
return false;
const {error, result} = await ApiGetGoodsSkus({productId : this.goodsId});
if(!HandleApiError(error, 'getGoodsSkus')){
//
this.stock = 0;
this.skuInfoData = result.map(i => {
this.stock += i.stock;
// i.attributeSymbolList = i.attributeSymbolList.split(',')
return i;
});
}
},
async getCommentCount (){
const {error, result} = await ApiGetCommentCount({
productId : this.goods.id
});
if(!HandleApiError(error, 'getCommentCount')){
this.commentCount = result.allCommentCount;
}
//
this.stock = 0;
this.skuInfoData = result.map(i => {
this.stock += i.stock;
// i.attributeSymbolList = i.attributeSymbolList.split(',')
return i;
},
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弹窗
@ -169,10 +200,7 @@ page {
width: 50rpx;
height: 50rpx;
left: 40rpx;
/* #ifdef H5 */
top: 40rpx;
/* #endif */
/* #ifndef H5 */
top: 128rpx;
/* #endif */
@ -209,15 +237,12 @@ page {
}
.select{
.box{
margin: 20rpx 30rpx;
background: $color-grey0;
border-radius: 16rpx;
}
.goods-desc{
margin: 20rpx 30rpx;
background: $color-grey0;
border-radius: 16rpx;
padding: 20rpx;
}
.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
* @Date: 2022-03-21 10:31:54
* @LastEditors: ch
* @LastEditTime: 2022-05-05 16:06:41
* @LastEditTime: 2022-05-30 17:43:22
* @Description: file content
-->
<template>
@ -33,7 +33,7 @@
<script>
import {ApiGetGoodsList} from '@/common/api/goods';
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 UiGoodsGroup from '../../../components/UiGoodsGroup.vue';
import BsEmpty from '../../../components/BsEmpty.vue';

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-05-21 16:30:22
* @LastEditTime: 2022-06-22 19:39:05
* @Description: file content
-->
<template>
@ -24,9 +24,9 @@
<view class="category">
<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">
<image class="category--image" :src="item.picture"></image>
<image class="category--image" :src="item.pictureUrl"></image>
</view>
<text class="category--title">{{item.name}}</text>
</view>
@ -44,39 +44,22 @@
</template>
<script>
import BsChoiceGoods from '@/components/BsChoiceGoods';
import Seckill from './components/Seckill';
import Pick from './components/Pick';
import Banner from './components/Banner';
import Seckill from './modules/Seckill';
import Pick from './modules/Pick';
import Banner from './modules/Banner';
import {ApiGetBannerData} from '@/common/api/index.js';
import {ApiGetHomeSeckill} from '@/common/api/seckill.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 {
components : {BsChoiceGoods, Pick, Banner, Seckill},
data(){
return {
scrollTop : 0,
bannerList: [
{ url : 'https://msb-edu-prod.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner6.jpg',
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 : [
],
bannerList: [],
categoryList : [],
recommendedGoodsList : [],
seckillData : {activityTimeVO:{}}
@ -86,6 +69,7 @@ export default {
this.getCategoryList();
this.getRecommendedGoodsList();
this.getSeckillList();
this.getBannerData();
},
onReachBottom(){
this.$refs.goodsGroup.next();
@ -106,10 +90,11 @@ export default {
},
methods : {
async getCategoryList(){
const {error, result} = await ApiGetCategoryNav();
if(result){
this.categoryList = result;
}
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_HARDCOVER
});
this.categoryList = result;
},
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(){
const {error, result} = await ApiGetHomeSeckill();
if(result){
this.seckillData = result
this.seckillData = result;
}
}
},
AdJump
}
}
</script>

@ -2,12 +2,13 @@
* @Author: ch
* @Date: 2022-03-23 10:31:12
* @LastEditors: ch
* @LastEditTime: 2022-05-21 20:09:18
* @LastEditTime: 2022-06-22 19:38:00
* @Description: file content
-->
<template>
<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--item">
<image class="desc--icon" src='@/static/index/bz.png'></image>
@ -29,6 +30,7 @@
</view>
</template>
<script>
import {AdJump} from '@/common/utils';
export default {
data(){
return {
@ -38,24 +40,13 @@ export default {
props:{
data : {
type : Array,
default : []
default : ()=>([])
}
},
methods:{
goDetail(idx){
let item = this.data[idx];
if(item.link){
// #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}`)
}
AdJump(item);
}
}
}

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-15 17:46:10
* @LastEditors: ch
* @LastEditTime: 2022-05-27 11:13:24
* @LastEditTime: 2022-07-13 18:20:38
* @Description: file content
-->
<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 === 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">
<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>
<u-popup class="cancel" :show="cancelShow" @close="closeCancel" round="16rpx" closeable>
<view class="cancel--title">取消订单原因</view>
@ -42,14 +49,17 @@
<UiButton type="gradual" :disabed="cancelValue == 0" @click="cancelOrder"></UiButton>
</view>
</u-popup>
<BsPay class="modal" :show.sync="payShow" :order="orderInfo"></BsPay>
<!-- <BsPay class="modal" :show.sync="payShow" :order="orderInfo"></BsPay> -->
</view>
</template>
<script>
import UiButton from '@/components/UiButton.vue'
import UiCell from '@/components/UiCell.vue'
import {ApiPutCancelOrder,ApiPutOrderReceive} from '@/common/api/order'
import BsPay from '../../../../components/BsPay.vue'
import {ApiPutCancelOrder,ApiPutOrderReceive} from '@/common/api/order';
import {ApiPostCashierPrepay} from '@/common/api/pay';
import BsPay from '../../../../components/BsPay.vue';
import ORDER from '@/common/dicts/order';
const ENV = process.env;
export default {
components: { UiButton, UiCell, BsPay },
props : {
@ -60,11 +70,10 @@ export default {
},
data(){
return {
ORDER,
//
cancelShow : false,
cancelValue : 0,
//
payShow : false
}
},
methods : {
@ -77,16 +86,16 @@ export default {
this.cancelValue = val;
},
async cancelOrder(){
const ooderId = this.$Route.query.id;
const orderId = this.orderInfo.orderId;
const {error, result} = await ApiPutCancelOrder({
cancelReasonType : this.cancelValue,
orderId : ooderId
orderId : orderId
});
if(error){
uni.$u.toast(error.message);
return false;
}
this.$Router.replace(`/orderDetail?id=${ooderId}`);
this.$Router.replace(`/orderDetail?id=${orderId}`);
//
},
/**
@ -100,39 +109,49 @@ export default {
success: async ({confirm}) => {
if(confirm){
const {error} = await ApiPutOrderReceive({
orderId : this.$Route.query.id
orderId : this.orderInfo.orderId
});
if(error){
uni.$toast(error.message);
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(){
// uni.$u.toast('')
this.$Router.push({
path : '/messageChat',
query : {
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
* @Date: 2022-03-31 17:53:43
* @LastEditors: ch
* @LastEditTime: 2022-05-05 20:43:19
* @LastEditTime: 2022-06-28 16:24:52
* @Description: file content
-->
<template>
@ -35,6 +35,8 @@ export default {
'5' : {name:'已收货', icon: require('@/static/order/fh.png')},
//
'6' : {name:'交易成功', icon: require('@/static/order/cg.png')},
//
'7' : {name:'交易成功', icon: require('@/static/order/cg.png')},
},
ctxCon : {},
startSecondNum : 0,

@ -2,13 +2,13 @@
* @Author: ch
* @Date: 2022-03-22 10:58:24
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:16
* @LastEditTime: 2022-07-13 18:21:13
* @Description: file content
-->
<template>
<view>
<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)">
{{item.name}}</text>
</view>
@ -19,7 +19,7 @@
<view class="orders" v-for="item in orderListData" :key="item.orderId">
<view class="orders--title">
<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>
<UiGoodsInfoMax v-for="item in item.products" :key="item.orderProductId"
:data="item" @click="$Router.push(`/orderDetail?id=${item.orderId}`)" />
@ -32,39 +32,49 @@
<view class="orders--footer">
<UiButton size="min" type="gradual"
v-if="item.orderStatus === 1" @click="pay(item)">去支付</UiButton>
<UiButton size="min" v-if="[2,3].includes(item.orderStatus)"
v-if="item.orderStatus === ORDER.STATUS.AWAIT_PAY" @click="handlePay(item)">去支付</UiButton>
<UiButton size="min" v-if="[ORDER.STATUS.CLOSE,ORDER.STATUS.AWAIT_PAY].includes(item.orderStatus)"
@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>
<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>
<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>
</template>
<script>
import BsEmpty from '@/components/BsEmpty.vue';
import UiButton from '@/components/UiButton.vue';
import { ApiGetOrderList, ApiPutOrderReceive } from '@/common/api/order';
import {ApiPostCashierPrepay} from '@/common/api/pay';
import BsPay from '../../components/BsPay.vue';
import UiGoodsInfo from '../../components/UiGoodsInfo.vue';
import UiGoodsInfoMax from '../../components/UiGoodsInfoMax.vue';
import UiMoney from '../../components/UiMoney.vue';
import ORDER from '@/common/dicts/order';
const ENV = process.env;
export default {
components: { BsEmpty, UiButton, BsPay, UiGoodsInfo, UiGoodsInfoMax, UiMoney },
data () {
return {
ORDER,
tabListData : [
{key : '-1', name : '全部'},
{key : '1', name : '待付款'},
{key : '3', name : '待发货'},
{key : '4', name : '待收货'}
// {key : '6', name : ''}
{key : ORDER.STATUS.AWAIT_PAY, name : '待付款'},
{key : ORDER.STATUS.FINISH_PAY, name : '待发货'},
{key : ORDER.STATUS.FINISH_SEND_GOODS, name : '待收货'},
{key : ORDER.STATUS.FINISH_TAKE_GOODS, name : '待评价'}
],
currentTabKey : this.$Route.query.tab || '-1',
orderListData : [],
@ -72,12 +82,11 @@ export default {
pageIndex : 1,
pageSize : 10,
payShow : false,
payOrder : null
}
},
onLoad(){
this.getOrderList()
this.getOrderList();
},
onReachBottom(){
this.next();
@ -87,6 +96,9 @@ export default {
* 切换tab 拉取当前分类第一页数据
*/
changeTab(key){
if(this.loadingStatus == 'loading' || this.currentTabKey == key){
return false;
}
this.currentTabKey = key;
this.pageIndex = 1;
this.orderListData = [];
@ -103,6 +115,7 @@ export default {
uni.$u.toast(error.message);
return false;
}
this.loadingStatus = 'finish';
//
if(result.records.length < this.pageSize){
this.loadingStatus = 'nomore';
@ -122,9 +135,25 @@ export default {
/**
* 立即支付
*/
pay(item){
this.payShow = true;
this.payOrder = item;
async handlePay(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);
return false;
}
this.$Router.push('/orderSuccess')
this.$Router.push(`/orderSuccess?orderId=${item.orderId}`)
}
}
})

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

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

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

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-20 14:14:53
* @LastEditors: ch
* @LastEditTime: 2022-05-26 16:33:14
* @LastEditTime: 2022-07-13 18:18:18
* @Description: file content
-->
<template>
@ -34,21 +34,6 @@
maxlength="50" placeholder="填写您想要备注的信息50字以内" />
</UiCell>
</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">
<u-cell title="商品总额" :value="`¥${orderInfo.productAmount}`" :border="false"></u-cell>
@ -71,11 +56,13 @@
import {GOODS_TYPE} from '@/common/dicts/goods';
import UiCell from '@/components/UiCell';
import {ApiPostSubmitOrder, ApiGetBeforeOrder, ApiGetBeforeCartOrder} from '@/common/api/order';
import {ApiPostCashierPrepay} from '@/common/api/pay';
import {ApiGetAddress } from '@/common/api/base';
import {Wxpay} from '@/common/utils';
import {Wxpay, Alipay} from '@/common/utils';
import UiButton from '@/components/UiButton.vue';
import UiWhiteBox from '../../components/UiWhiteBox.vue';
import UiGoodsInfo from '../../components/UiGoodsInfo.vue';
const ENV = process.env;
export default {
components : {UiCell, UiButton, UiWhiteBox, UiGoodsInfo },
data(){
@ -84,7 +71,6 @@ export default {
address : {},
userMessage : '',
orderInfo : {},
payType : 'wxpay',
productType : this.$Route.query.productType,
}
},
@ -189,11 +175,28 @@ export default {
uni.$u.toast(error.message);
return false;
}
if(this.payType === 'wxpay'){
Wxpay({orderId : result.orderId, openId : this.$store.state.openId});
}else{
uni.$u.toast('暂不支持支付宝支付');
let payType = 'wxjsapi'
if(!this.$store.state.openId){
payType = 'h5'
}
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
* @Date: 2022-03-21 18:08:07
* @LastEditors: ch
* @LastEditTime: 2022-05-05 10:52:27
* @LastEditTime: 2022-06-13 14:25:12
* @Description: file content
-->
<template>

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

Loading…
Cancel
Save