Compare commits

..

No commits in common. 'main' and 'fix/0523-ch' have entirely different histories.

@ -1,3 +0,0 @@
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

@ -1,3 +0,0 @@
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

@ -1,3 +0,0 @@
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

@ -1,3 +0,0 @@
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,7 +4,6 @@ node_modules/
unpackage/
dist/
.history/
.hbuilderx/
env.js
yarn.lock

@ -1,4 +0,0 @@
FROM nginx
COPY dist/build/h5 /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

@ -5,28 +5,18 @@
* @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';
@ -49,20 +39,17 @@ 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'
@ -73,7 +60,7 @@ export const IsEmail = (str) => {....}
}
// user.vue
improt {ApiGetUserInfo} from '@/common/api/xxapi.js';
const getUserInfo = async () =>{
const {error, result} = await ApiGetUserInfo();
if(error){
@ -84,8 +71,6 @@ export const IsEmail = (str) => {....}
}
```
## 图片
- 按 pages 目录结果放置图片
- 有公共使用的图片请放到 static/common 文件夹内
- 按pages目录结果放置图片
- 有公共使用的图片请放到static/common文件夹内

@ -1,54 +0,0 @@
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
app: $IMAGES
name: $IMAGES
namespace: yanxuan
spec:
progressDeadlineSeconds: 600
replicas: 1
selector:
matchLabels:
app: $IMAGES
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
template:
metadata:
labels:
app: $IMAGES
spec:
imagePullSecrets:
- name: aliyun-docker-hub
containers:
- image: '$REGISTRY/$DOCKERHUB_NAMESPACE/$IMAGES:$BUILD_NUMBER'
name: app
ports:
- containerPort: $JAR_PORD
protocol: TCP
resources:
limits:
cpu: '0.5'
memory: 500Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
---
kind: Service
apiVersion: v1
metadata:
name: $IMAGES
namespace: yanxuan
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: $IMAGES
type: ClusterIP

@ -0,0 +1,46 @@
/*
* @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;`);

@ -1,26 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name localhost default_server;
client_max_body_size 200m;
location / {
if ($request_filename ~* .*\.(?:htm|html)$) {
add_header Cache-Control "no-store";
}
root /usr/share/nginx/html;
try_files $uri @index ;
}
location @index {
add_header Cache-Control "no-store" ;
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri/index.html /index.html;
}
error_page 405 =200 $uri;
}

23183
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,18 +3,15 @@
"version": "0.1.0",
"private": true,
"scripts": {
"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",
"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",
"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-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: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: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",
@ -32,9 +29,6 @@
"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",
@ -77,36 +71,35 @@
"@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",
"vue": "^2.6.11",
"vuex": "^3.2.0"
"uview-ui": "^2.0.29"
},
"devDependencies": {
"@babel/runtime": "~7.12.0",
"@dcloudio/types": "^2.6.7",
"@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",
"@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",
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"babel-plugin-import": "1.13.8",
"cross-env": "7.0.3",
"jest": "25.5.4",
"babel-plugin-import": "^1.11.0",
"cross-env": "^7.0.2",
"jest": "^25.4.0",
"mini-types": "*",
"miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0",

@ -1,10 +1,3 @@
<!--
* @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">
@ -21,7 +14,7 @@
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body class="page">
<body>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>

@ -1,18 +0,0 @@
/*
* @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,34 +2,13 @@
* @Author: ch
* @Date: 2022-04-06 17:29:13
* @LastEditors: ch
* @LastEditTime: 2022-05-31 11:18:44
* @LastEditTime: 2022-04-15 14:17:14
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
import {ToAsyncAwait, 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));
/**
* 获取收货地址
*/

@ -1,66 +0,0 @@
/*
* @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,16 +1,48 @@
/*
* @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';
// /*
// * @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';
/**
* 获取soket登录秘钥
*/
export const ApiGetSoketTicket = () => ToAsyncAwait(MsbRequestTk.get(`${BASE_URL}/ticket`, {
ticketType: 'CONNECT_TICKET'
}));
// /**
// * 系统消息心跳
// */
// 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
// });

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-29 17:38:17
* @LastEditors: ch
* @LastEditTime: 2022-06-23 16:21:32
* @LastEditTime: 2022-05-10 16:14:53
* @Description: file content
*/
import {ToAsyncAwait, MsbRequestTk} from '@/common/utils';
@ -84,11 +84,8 @@ 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))
/**

@ -1,51 +0,0 @@
/*
* @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,12 +2,13 @@
* @Author: ch
* @Date: 2022-04-28 16:30:54
* @LastEditors: ch
* @LastEditTime: 2022-06-29 17:16:50
* @LastEditTime: 2022-05-17 20:07:26
* @Description: file content
*/
import {ToAsyncAwait, MsbRequest, MsbRequestTk} from '@/common/utils';
const BASE_URL = '/mall/trade';
// 第三方鉴权服务
const AUTH_URL = '/third';
const APPID = 'wxd2015f0c56defa02';
@ -32,3 +33,24 @@ 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));

@ -1,42 +0,0 @@
/*
* @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
}

@ -1,33 +0,0 @@
/*
* @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-06-22 11:23:02
* @LastEditTime: 2022-05-26 17:00:06
* @Description: file content
*/
@ -11,25 +11,13 @@ export const ORDER_STATUS = {
// 待支付
AWAIT_PAY: 1
}
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
}
export const ORDER_TYPE = {
//(1, "普通订单"),
NORMAL: 1,
//(2, "免费订单"),
FREE: 2,
//(3, "秒杀订单"),
SECKILL: 3,
//(4, "虚拟商品订单"),
VIRTUAL : 4
}

@ -2,482 +2,362 @@
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-06-14 17:24:14
* @LastEditTime: 2022-05-24 22:51:47
* @Description: file content
*/
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
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(),
};
};
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);
}
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-07-12 18:31:15
* @LastEditTime: 2022-03-18 11:11:05
* @Description: file content
*/
import {RouterMount,createRouter} from 'uni-simple-router';
@ -13,11 +13,6 @@ 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-06-22 15:31:09
* @LastEditTime: 2022-05-21 11:38:51
* @Description: file content
*/
import Vue from 'vue'
@ -17,22 +17,16 @@ const
// 地址列表
ADDRESS = 'ads',
// oppenId
OPPED_ID = 'oi',
// 每个浏览器创建一个UUID作为同一个用户的标识
UUID = 'uid',
// 评价图片预览数据
COMMENT_PREVIEW = 'comment_preview';
OPPED_ID = 'oi';
export default new Vuex.Store({
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) || '{}'),
state : {
token : uni.getStorageSync(TOKEN) || '',
userInfo : JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address : JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
imData : [],
imMsgCount : 0
imMsgCount : 0,
openId : uni.getStorageSync(OPPED_ID) || ''
},
mutations:{
SET_TOKEN (state, token = ''){
@ -47,23 +41,15 @@ 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 : {

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

@ -2,22 +2,17 @@
* @Author: ch
* @Date: 2022-03-22 16:52:28
* @LastEditors: ch
* @LastEditTime: 2022-06-29 17:28:39
* @LastEditTime: 2022-06-29 17:22:32
* @LastEditTime: 2022-05-20 11:42:33
* @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, ...uploadFileOss, ...alipay}
export default { ...util, ...requset, ...im, ...wxpay}

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

@ -1,46 +0,0 @@
/*
* @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,20 +2,18 @@
* @Author: ch
* @Date: 2022-03-17 19:15:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:39:35
* @LastEditTime: 2022-05-23 11:40:29
* @Description: 一些无法归类的公共方法容器
*/
import {
toAsyncAwait as ToAsyncAwait,
isPhone as IsPhone,
formatDate as FormatDate,
creatUuid as CreateUUID,
formatSearchJson as FormatSearchJson,
formatJsonSearch as FormatJsonSearch
toAsyncAwait as ToAsyncAwait,
isPhone as IsPhone,
formatDate as FormatDate,
creatUuid as CreateUUID,
formatSearchJson as FormatSearchJson
} from "js-util-all";
import {AD_JUMP_TYPE} from '@/common/dicts/ad';
/**
* 首次运行时把定时器赋值给一个变量 第二次执行时
@ -24,76 +22,28 @@ import {AD_JUMP_TYPE} from '@/common/dicts/ad';
* 没有执行清除定时器 超过一定时间后触发回调函数
*/
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)
}
}
/**
* 广告跳转
* 兼容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;
let timer
return function() {
const that = this
const _args = arguments // 存一下传入的参数
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
fn.apply(that, _args)
}, delay)
}
}
// 工具类的文件需要把文件提供的工具类统一放最下方做一个统一输出
export {
// async await 标识结果处理
ToAsyncAwait,
// 判断是否为手机号
IsPhone,
// 时间格式化
FormatDate,
FormatSearchJson,
FormatJsonSearch,
CreateUUID,
// 防抖函数
Debounce,
// 广告跳转
AdJump,
HandleApiError
// async await 标识结果处理
ToAsyncAwait,
// 判断是否为手机号
IsPhone,
// 时间格式化
FormatDate,
FormatSearchJson,
CreateUUID,
// 防抖函数
Debounce
}

@ -2,12 +2,12 @@
* @Author: ch
* @Date: 2022-04-29 14:26:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:40:10
* @LastEditTime: 2022-05-26 20:28:48
* @Description: file content
*/
import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/pay';
const ENV = process.env;
import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/wx';
import ENV from '@/common/config/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.payDataInfo;
const par = result.dataInfo;
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.payDataInfo;
const par = result.dataInfo;
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.VUE_APP_STATIC_URL}/payResult?orderId=${orderId}&payType=wxh5`);
window.location.href = `${result.payDataInfo.h5Url}&redirect_url=${redirect_url}`;
const redirect_url = decodeURIComponent(`${ENV.staticUrl}/payResult?orderId=${orderId}&payType=wxh5`);
window.location.href = `${result.dataInfo.payUrl}&redirect_url=${redirect_url}`;
}
// #endif

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-20 16:45:27
* @LastEditors: ch
* @LastEditTime: 2022-06-22 19:34:13
* @LastEditTime: 2022-05-06 14:26:57
* @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;

@ -1,85 +0,0 @@
<!--
* @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>

@ -1,66 +0,0 @@
<!--
* @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>

@ -1,93 +0,0 @@
<!--
* @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>

@ -1,56 +0,0 @@
<!--
* @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>

@ -1,138 +0,0 @@
<!--
* @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>

@ -1,96 +0,0 @@
<!--
* @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>

@ -1,47 +0,0 @@
<!--
* @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-06-29 17:27:12
* @LastEditTime: 2022-05-05 11:08:44
* @Description: file content
-->
<template>
@ -12,7 +12,7 @@
<script>
import UiRadioPicker from './UiRadioPicker.vue'
import { ApiPostWxPay } from '@/common/api/order';
import { Wxpay, Alipay } from '@/common/utils';
import { Wxpay } from '@/common/utils';
export default {
components: { UiRadioPicker },
props : {
@ -32,19 +32,13 @@ 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;
@ -52,8 +46,7 @@ export default {
Wxpay({orderId, openId: this.$store.state.openId});
this.close();
}else{
// uni.$u.toast('');
Alipay({orderId})
uni.$u.toast('暂不支持支付宝支付');
}
},
close(){

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

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

@ -1,6 +1,6 @@
{
"name" : "马士兵严选",
"appid" : "__UNI__5FEB250",
"appid" : "__UNI__3FB31B6",
"description" : "",
"versionName" : "1.0.1",
"versionCode" : "100",
@ -40,14 +40,10 @@
"<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" : {
"dSYMs" : false
},
"ios" : {},
/* SDK */
"sdkConfigs" : {
"ad" : {},
@ -56,18 +52,39 @@
"__platform__" : [ "android" ],
"appid" : "wx17b34a4a90ef18f7",
"UniversalLinks" : ""
},
"alipay" : {
"__platform__" : [ "android" ]
}
}
},
"icons" : {
"android" : {
"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"
"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"
}
}
}
}
@ -101,7 +118,20 @@
"base" : ""
},
"devServer" : {
"port" : 8080
"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"
}
}
},
"optimization" : {
"treeShaking" : {

@ -0,0 +1,75 @@
{
"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,13 +10,6 @@
"backgroundColor" : "#69ADE5"
}
},
{
"path": "pages/webView",
"aliasPath" : "/webView",
"style": {
"navigationBarTitleText": "收银台"
}
},
{
"path": "pages/login",
"aliasPath" : "/login",
@ -65,42 +58,6 @@
"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",
@ -220,20 +177,6 @@
"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-06-28 16:38:33
* @LastEditTime: 2022-05-24 09:57:07
* @Description: file content
-->
<template>
@ -38,11 +38,6 @@
<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">
@ -140,10 +135,6 @@ 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-05-11 11:45:08
* @LastEditors: ch
* @LastEditTime: 2022-06-14 12:55:27
* @LastEditTime: 2022-05-24 22:54:29
* @Description: file content
-->
<template>
@ -158,11 +158,11 @@ export default {
this.msgCtx += str;
},
sendGoods(){
this.send({...this.simpleGoods, customType:'goodsInfo'}, MSG_TYPE.CUSTOM);
this.send(this.simpleGoods, MSG_TYPE.CUSTOM);
this.goodsShow = false;
},
sendOrder(){
this.send({...this.simpleOrder, customType : 'orderInfo'}, MSG_TYPE.CUSTOM);
this.send(this.simpleOrder, MSG_TYPE.CUSTOM);
this.orderShow = false;
},
uploadImg(val){

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 16:13:00
* @LastEditors: ch
* @LastEditTime: 2022-06-17 16:31:20
* @LastEditTime: 2022-05-27 15:32:18
* @Description: file content
-->
<template>
@ -18,14 +18,11 @@
<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 === 'app_push'">
{{item.lastMessage.payload.link ? '[链接]' : item.lastMessage.payload.content}}
</template>
<template v-if="item.lastMessage.payload.customType === 'transferWaiterSession'">
[客服转移]
<template v-if="item.lastMessage.payload.customType === 'orderAutoDelivery'">
{{item.lastMessage.payload.content}}
</template>
<template v-else>
{{item.lastMessage.payload.content || '[未知消息]'}}
[链接]
</template>
</template>
<template v-if="item.lastMessage.type == msgType.IMG">[]</template>
@ -43,7 +40,7 @@
<script>
import BsEmpty from '../../../components/BsEmpty.vue';
import {MSG_TYPE} from '@/common/dicts/im';
import {FormatDate, Im} from '@/common/utils';
import {FormatDate} from '@/common/utils';
export default {
components: { BsEmpty },
data (){
@ -59,20 +56,18 @@ export default {
},
computed:{
sessionData (){
return this.$store.state.imData.sort((a,b) => b.updateTimeStamp - a.updateTimeStamp);
return this.$store.state.imData;
}
},
methods:{
FormatDate,
openMsg(item){
Im.setCurSessionId(item.id);
if(item.type === 4){
if(JSON.parse(item.payload).type === 'system'){
this.$Router.push(`/messageSystem?sessionId=${item.id}`);
return false;
}
if(item.type === 3){
this.$Router.push(`/messageChat?sessionId=${item.id}`);
}else{
this.$Router.push(`/messageSystem?sessionId=${item.id}`);
}
this.$Router.push(`/messageChat?sessionId=${item.id}`);
}
}
}
@ -112,8 +107,6 @@ 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-06-02 18:07:09
* @LastEditTime: 2022-05-27 17:02:59
* @Description: file content
-->
<template>
@ -21,6 +21,7 @@
<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>
@ -77,7 +78,13 @@ export default {
},
async getHistoryMsg(){
this.loading = true;
await ToAsyncAwait(Im.getHistoryMsg());
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
}
}));
},
/**
* 把当前会话消息置为已读

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-28 15:38:23
* @LastEditors: ch
* @LastEditTime: 2022-06-13 20:49:32
* @LastEditTime: 2022-05-17 11:44:50
* @Description: file content
-->
<template>
@ -38,7 +38,7 @@ export default {
nickname : this.userInfo.nickname
});
if(error){
uni.$u.toast(error.message);
ui.$u.totas(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-06-13 20:59:54
* @LastEditTime: 2022-05-24 09:57:14
* @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){
uni.$u.toast(error.message);
ui.$u.totas(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-30 17:44:51
* @LastEditTime: 2022-05-17 11:29:38
* @Description: file content
-->
<template>
@ -10,7 +10,7 @@
</template>
<script>
import PageCtx from './modules/PageCtx';
import PageCtx from './components/PageCtx';
export default {
components : {PageCtx},
onShow(){

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

@ -17,11 +17,10 @@
<!-- 右侧 二级分类 -->
<scroll-view class="cate-right" @scrolltolower="reachBottom" :scroll-top="scrollTop" :scroll-y="true">
<image class="cate-tow-img" v-if="curTwoCategory.adPictureUrl" :src="curTwoCategory.adPictureUrl"
@click="handleAdJump(curTwoCategory)"></image>
<image class="cate-tow-img" :src="`https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/category${categoryData[curIndex].id}.jpg`"></image>
<!-- <view @click="onTargetGoodsList(item.id)"> -->
<view class="cate-tow-group" :class="idx === curTwoCategory.children.length - 1 ? 'cate-tow-group__last' :''"
v-for="(item, idx) in curTwoCategory.children" :key="idx">
<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">
<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}`)">
@ -31,9 +30,9 @@
</view>
</view>
<!-- </view> -->
<BsEmpty class="empty" v-if="!curTwoCategory.children.length && !curTwoCategory.isLoading"
<BsEmpty class="empty" v-if="!categoryData[curIndex].children.length && !categoryData[curIndex].isLoading"
:icon="require('@/static/common/empty_goods.png')" />
<u-loadmore status="loading" v-if="curTwoCategory.isLoading" />
<u-loadmore status="loading" v-if="categoryData[curIndex].isLoading" />
</scroll-view>
</view>
<BsEmpty v-if="!categoryData.length && !isLoading" />
@ -46,9 +45,6 @@
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() {
@ -63,11 +59,6 @@ export default {
isLoading: true,
};
},
computed:{
curTwoCategory(){
return this.categoryData[this.curIndex];
}
},
onLoad() {
//
this.getCategoryData();
@ -103,12 +94,11 @@ export default {
item.children = [];
item.isLoading = true;
this.getTwoCategoryData(item);
this.getTwoCategoryAd(item);
return item;
});
this.isLoading = false;
},
/**
* 初始化分类列表数据
* @param {Object} result
@ -117,24 +107,6 @@ 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
});
}
},
};

@ -1,268 +0,0 @@
<!--
* @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>

@ -1,203 +0,0 @@
<!--
* @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>

@ -1,109 +0,0 @@
<!--
* @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>

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

@ -1,90 +0,0 @@
<!--
* @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>

@ -1,83 +0,0 @@
<!--
* @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-30 17:43:22
* @LastEditTime: 2022-05-05 16:06:41
* @Description: file content
-->
<template>
@ -33,7 +33,7 @@
<script>
import {ApiGetGoodsList} from '@/common/api/goods';
import BsChoiceGoods from "@/components/BsChoiceGoods.vue";
import Sort from "./modules/Sort.vue";
import Sort from "./components/Sort.vue";
import UiPageHeader from '@/components/UiPageHeader.vue';
import UiGoodsGroup from '../../../components/UiGoodsGroup.vue';
import BsEmpty from '../../../components/BsEmpty.vue';

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-06-22 19:39:05
* @LastEditTime: 2022-05-21 16:30:22
* @Description: file content
-->
<template>
@ -24,9 +24,9 @@
<view class="category">
<view class="category--item" v-for="item in categoryList" :key="item.id"
@click="AdJump(item)">
@click="$Router.push(`/goodsList?categoryId=${item.id}`)">
<view class="category--image-box">
<image class="category--image" :src="item.pictureUrl"></image>
<image class="category--image" :src="item.picture"></image>
</view>
<text class="category--title">{{item.name}}</text>
</view>
@ -44,22 +44,39 @@
</template>
<script>
import BsChoiceGoods from '@/components/BsChoiceGoods';
import Seckill from './modules/Seckill';
import Pick from './modules/Pick';
import Banner from './modules/Banner';
import Seckill from './components/Seckill';
import Pick from './components/Pick';
import Banner from './components/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: [],
categoryList : [],
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 : [
],
recommendedGoodsList : [],
seckillData : {activityTimeVO:{}}
@ -69,7 +86,6 @@ export default {
this.getCategoryList();
this.getRecommendedGoodsList();
this.getSeckillList();
this.getBannerData();
},
onReachBottom(){
this.$refs.goodsGroup.next();
@ -90,11 +106,10 @@ export default {
},
methods : {
async getCategoryList(){
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_HARDCOVER
});
this.categoryList = result;
const {error, result} = await ApiGetCategoryNav();
if(result){
this.categoryList = result;
}
},
async getRecommendedGoodsList(){
@ -104,19 +119,12 @@ 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,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 15:36:46
* @LastEditors: ch
* @LastEditTime: 2022-06-13 10:20:21
* @LastEditTime: 2022-05-24 09:57:06
* @Description: file content
-->
<template>
@ -119,7 +119,9 @@ export default {
// IM
ImInit().then(() => {
//
Im.getSessionList();
Im.getSessionList({
content: { sysId : 1 }
});
});
this.goBack();

@ -1,155 +0,0 @@
<!--
* @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>

@ -1,74 +0,0 @@
<!--
* @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>

@ -1,137 +0,0 @@
<!--
* @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-04-15 17:46:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 18:20:38
* @LastEditTime: 2022-05-27 11:13:24
* @Description: file content
-->
<template>
@ -13,17 +13,10 @@
<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="handlePay"></UiButton>
<UiButton class="footer--btn" type="gradual" @click="payShow = true">去支付</UiButton>
</template>
<u-popup class="cancel" :show="cancelShow" @close="closeCancel" round="16rpx" closeable>
<view class="cancel--title">取消订单原因</view>
@ -49,17 +42,14 @@
<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 {ApiPostCashierPrepay} from '@/common/api/pay';
import BsPay from '../../../../components/BsPay.vue';
import ORDER from '@/common/dicts/order';
const ENV = process.env;
import {ApiPutCancelOrder,ApiPutOrderReceive} from '@/common/api/order'
import BsPay from '../../../../components/BsPay.vue'
export default {
components: { UiButton, UiCell, BsPay },
props : {
@ -70,10 +60,11 @@ export default {
},
data(){
return {
ORDER,
//
cancelShow : false,
cancelValue : 0,
//
payShow : false
}
},
methods : {
@ -86,16 +77,16 @@ export default {
this.cancelValue = val;
},
async cancelOrder(){
const orderId = this.orderInfo.orderId;
const ooderId = this.$Route.query.id;
const {error, result} = await ApiPutCancelOrder({
cancelReasonType : this.cancelValue,
orderId : orderId
orderId : ooderId
});
if(error){
uni.$u.toast(error.message);
return false;
}
this.$Router.replace(`/orderDetail?id=${orderId}`);
this.$Router.replace(`/orderDetail?id=${ooderId}`);
//
},
/**
@ -109,49 +100,39 @@ export default {
success: async ({confirm}) => {
if(confirm){
const {error} = await ApiPutOrderReceive({
orderId : this.orderInfo.orderId
orderId : this.$Route.query.id
});
if(error){
uni.$toast(error.message);
return false;
}
this.$Router.push(`/orderSuccess?orderId=${this.orderInfo.orderId}`);
this.$Router.push('/orderSuccess');
}
}
})
// 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-06-28 16:24:52
* @LastEditTime: 2022-05-05 20:43:19
* @Description: file content
-->
<template>
@ -35,8 +35,6 @@ 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,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-31 14:26:09
* @LastEditors: ch
* @LastEditTime: 2022-06-22 11:22:41
* @LastEditTime: 2022-05-26 17:13:33
* @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 './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'
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'
export default {
components: { UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, OrderInfo, LogisitcsInfo, Operation },
data(){
return {
ORDER,
ORDER_TYPE,
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,13 +2,13 @@
* @Author: ch
* @Date: 2022-03-22 10:58:24
* @LastEditors: ch
* @LastEditTime: 2022-07-13 18:21:13
* @LastEditTime: 2022-05-24 09:57:16
* @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="[ORDER.STATUS.AWAIT_PAY,ORDER.STATUS.FINISH_PAY].includes(item.orderStatus) && 'orders--status__warn'">{{item.orderStatusDesc}}</text>
<text class="orders--status" :class="[1,3].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,49 +32,39 @@
<view class="orders--footer">
<UiButton size="min" type="gradual"
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)"
v-if="item.orderStatus === 1" @click="pay(item)">去支付</UiButton>
<UiButton size="min" v-if="[2,3].includes(item.orderStatus)"
@click="$Router.push(`/orderDetail?id=${item.orderId}`)">查看详情</UiButton>
<UiButton size="min" v-if="item.orderStatus >= ORDER.STATUS.FINISH_SEND_GOODS"
<UiButton size="min" v-if="item.orderStatus >= 4"
@click="$Router.push(`/logisitcsInfo?orderId=${item.orderId}`)">查看物流</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>
<UiButton size="min" type="gradual" v-if="item.orderStatus === 4" @click="receive(item)"></UiButton>
</view>
</view>
<u-loadmore :status="loadingStatus" v-if="loadingStatus !== 'nomore'"/>
<u-loadmore :status="loadingStatus" v-if="loadingStatus === 'loading'"/>
<!-- <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 : 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 : '待评价'}
{key : '1', name : '待付款'},
{key : '3', name : '待发货'},
{key : '4', name : '待收货'}
// {key : '6', name : ''}
],
currentTabKey : this.$Route.query.tab || '-1',
orderListData : [],
@ -82,11 +72,12 @@ export default {
pageIndex : 1,
pageSize : 10,
payShow : false,
payOrder : null
}
},
onLoad(){
this.getOrderList();
this.getOrderList()
},
onReachBottom(){
this.next();
@ -96,9 +87,6 @@ export default {
* 切换tab 拉取当前分类第一页数据
*/
changeTab(key){
if(this.loadingStatus == 'loading' || this.currentTabKey == key){
return false;
}
this.currentTabKey = key;
this.pageIndex = 1;
this.orderListData = [];
@ -115,7 +103,6 @@ export default {
uni.$u.toast(error.message);
return false;
}
this.loadingStatus = 'finish';
//
if(result.records.length < this.pageSize){
this.loadingStatus = 'nomore';
@ -135,25 +122,9 @@ export default {
/**
* 立即支付
*/
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
pay(item){
this.payShow = true;
this.payOrder = item;
},
/**
@ -173,7 +144,7 @@ export default {
uni.$toast(error.message);
return false;
}
this.$Router.push(`/orderSuccess?orderId=${item.orderId}`)
this.$Router.push('/orderSuccess')
}
}
})

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-18 15:28:14
* @LastEditors: ch
* @LastEditTime: 2022-06-22 11:22:21
* @LastEditTime: 2022-05-17 17:55:56
* @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" v-if="orderInfo.orderType !== ORDER.TYPE.VIRTUAL">
<UiWhiteBox class="company">
<text class="company--name">{{orderInfo.companyName}}</text>
<view class="company--no">
<text>{{orderInfo.trackingNo}}</text>
@ -38,12 +38,10 @@ 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-06-28 16:46:43
* @LastEditTime: 2022-04-29 23:03:47
* @Description: file content
-->
<template>
@ -10,8 +10,7 @@
<image class="icon" src="@/static/order/paySuccess.png"/>
<view class="title">交易成功</view>
<view class="btns">
<UiButton class="btn" @click="$Router.replaceAll('/')"></UiButton>
<UiButton class="btn" type="primaryLine" @click="$Router.replace(`/comment?orderId=${orderId}`)"></UiButton>
<UiButton class="btn" type="primaryLine" @click="$Router.replaceAll('/')"></UiButton>
</view>
</view>
</template>
@ -19,11 +18,6 @@
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-07-13 18:41:57
* @LastEditTime: 2022-05-06 10:49:00
* @Description: file content
-->
@ -55,10 +55,10 @@ export default {
this.reuqestNum++;
const {error, result} = await ApiGetOrderPaySatus({orderId : this.$Route.query.orderId});
if(error){
uni.$u.toast(error.message);
uin.$u.toast(error.message);
return false
}
if(!result.isSuccess && this.reuqestNum < 10){
if(!result.isSuccess && this.reuqestNum < 5){
setTimeout(()=>{
this.getOrderInfo();
}, 1000)
@ -69,11 +69,9 @@ export default {
},
back(){
const payType = this.$Route.query.payType;
if(payType === 'wxjsapi'){
this.$Router.back();
}else if(payType === 'h5'){
history.back(2);
}else if(payType === 'appWx'){
if(payType !== 'wxjsapi'){
this.$Router.back(2);
}else{
this.$Router.back();
}
}

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

Loading…
Cancel
Save