Compare commits

..

No commits in common. 'main' and 'feature/im-0602-ch' have entirely different histories.

@ -1,3 +1,4 @@
VUE_APP_BASE_URL = https://k8s-horse-gateway.mashibing.cn
VUE_APP_STATIC_URL = https://k8s-shop-app.mashibing.cn
#VUE_APP_IM_URL = ws://192.168.10.94:8090
VUE_APP_IM_URL = wss://k8s-horse-gateway.mashibing.cn

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

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

@ -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文件夹内

@ -0,0 +1,47 @@
/*
* @Author: ch
* @Date: 2022-05-05 14:40:00
* @LastEditors: ch
* @LastEditTime: 2022-06-09 11:25:44
* @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 : 'ws://192.168.10.94:8090'
imUrl : 'wss://k8s-horse-gateway.mashibing.cn'
},
test : {
baseUrl: 'https://k8s-horse-gateway.mashibing.cn',
staticUrl : 'https://k8s-shop-app.mashibing.cn',
imUrl : 'wss://k8s-horse-gateway.mashibing.cn'
},
beta : {
baseUrl: 'https://you-gateway.mashibing.com',
staticUrl : 'https://you-app.mashibing.com',
imUrl : 'wss://you-gateway.mashibing.com'
},
prod : {
baseUrl: 'https://you-gateway.mashibing.com',
staticUrl : 'https://you-app.mashibing.com',
imUrl : 'wss://you-gateway.mashibing.com'
}
}
let curEnvConfig = null;
const argv = global.process.argv;
for(key in envConfig){
if(argv.includes(`--ENV:${key}`)){
curEnvConfig = envConfig[key];
break;
}
}
if(!curEnvConfig){
curEnvConfig = envConfig.dev;
}
fs.writeFileSync(`${path.resolve(__dirname, './src/common/config')}/env.js`,
`const ENV = ${JSON.stringify(curEnvConfig)}; export default ENV;`);

23183
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -3,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,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));

@ -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,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,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-18 14:54:47
* @LastEditors: ch
* @LastEditTime: 2022-06-14 17:24:14
* @LastEditTime: 2022-06-14 10:52:01
* @Description: file content
*/
import { CreateUUID, FormatDate, ToAsyncAwait } from "@/common/utils";
@ -34,7 +34,6 @@ const fromatPotoReq = (traceId, traceType, content) => {
};
};
class MsbIm {
defaultOption = {
ioKey: 'traceId',
@ -201,7 +200,7 @@ class MsbIm {
...historyData,
{
fromAvatar: ctx.session.fromAvatar,
fromId: ctx.session.fromId,
fromId: ctx.fromId,
fromNickname: ctx.session.fromNickname,
id: ctx.sessionId,
lastMessage: ctx,
@ -309,7 +308,7 @@ class MsbIm {
async getHistoryMsg() {
const curSessionIdx = this.sessionData.findIndex((i) => i.id === this.curSessionId);
const curSession = this.sessionData[curSessionIdx];
console.log(curSession, this.curSessionId, 'this.curSessionId');
console.log(curSession, this.curSessionId,'this.curSessionId');
const msgList = curSession.messageList || [];
const par = {
traceId: CreateUUID(),
@ -382,7 +381,6 @@ class MsbIm {
msgCtx.payload = JSON.parse(msgCtx.payload);
}
// 点发送,立即把消息加入消息列表,标记为发送中状态
curSession.lastMessage = msgCtx;
curSession.messageList.push(msgCtx);
this.setSessionData(this.sessionData);
@ -401,7 +399,6 @@ class MsbIm {
}
}
let newData = [...this.sessionData];
curSession.lastMessage = msgCtx;
newData[index] = curSession;
this.setSessionData(newData);
if (error) {

@ -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-06-09 14:43:07
* @Description: file content
*/
import Vue from 'vue'
@ -19,18 +19,15 @@ const
// oppenId
OPPED_ID = 'oi',
// 每个浏览器创建一个UUID作为同一个用户的标识
UUID = 'uid',
// 评价图片预览数据
COMMENT_PREVIEW = 'comment_preview';
UUID = 'uid';
export default new Vuex.Store({
state: {
token: uni.getStorageSync(TOKEN) || '',
userInfo: JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address: JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
state : {
token : uni.getStorageSync(TOKEN) || '',
userInfo : JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address : JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
openId: uni.getStorageSync(OPPED_ID) || '',
uuid: uni.getStorageSync(UUID) || '',
comment_preview: JSON.parse(uni.getStorageSync(COMMENT_PREVIEW) || '{}'),
uuid : uni.getStorageSync(UUID) || '',
imData : [],
imMsgCount : 0
},
@ -55,10 +52,6 @@ export default new Vuex.Store({
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 ;
},

@ -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,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-20 11:00:07
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:37:52
* @LastEditTime: 2022-06-13 10:11:33
* @Description: file content
*/
@ -11,7 +11,7 @@ import { ToAsyncAwait, FormatJsonSearch } 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,
@ -31,7 +31,7 @@ const ImInit = async () => {
avatar : $store.state.userInfo.avatar
})
await ToAsyncAwait(Im.init({
url: `${ENV.VUE_APP_IM_URL}/ws${par}`
url: `${ENV.imUrl}/ws${par}`
}))
};

@ -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,23 @@
* @Author: ch
* @Date: 2022-03-17 17:42:32
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:39:07
* @LastEditTime: 2022-06-10 15:59:04
* @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法
*/
import MsbUniRequest from '@/common/plugins/msbUniRequest';
import $store from '@/common/store';
import ENV from '@/common/config/env';
import store from '../store';
import { CreateUUID } from '@/common/utils';
const ENV = process.env;
// 获取已有的UUID没则创建一个并保存到locaStorage中下次使用
let uuid = $store.state.uuid
let uuid = store.state.uuid
if (!uuid) {
uuid = CreateUUID(16, 2);
$store.commit('SET_UUID', uuid);
}
/**
* 接口返回成功结果统一处理
* @param {*} response
@ -82,7 +84,8 @@ const clearRepeat = (option) =>{
// 不需要token的接口封装
const MsbRequest = new MsbUniRequest();
MsbRequest.baseUrl = ENV.VUE_APP_BASE_URL;
console.log(process.env,'process.envprocess.envprocess.env');
MsbRequest.baseUrl = ENV.baseUrl;
MsbRequest.use('request', (option) => {
if(option.header.repeat){
@ -102,29 +105,29 @@ 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,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-17 19:15:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:39:35
* @LastEditTime: 2022-06-02 14:55:45
* @Description: 一些无法归类的公共方法容器
*/
@ -15,6 +15,7 @@ import {
formatJsonSearch as FormatJsonSearch
} from "js-util-all";
import ENV from '@/common/config/env';
import {AD_JUMP_TYPE} from '@/common/dicts/ad';
/**
@ -42,6 +43,11 @@ const Debounce = (fn, delay) => {
* @param {*} link
*/
const AdJump = (item) => {
// if (!/^(http|https):\/\/./.test(link)) {
// uni.$u.toast('非法链接,暂不跳转!');
// return false;
// }
console.log(item);
switch (item.jumpType) {
case AD_JUMP_TYPE.GOODS:
uni.navigateTo({
@ -65,21 +71,6 @@ const AdJump = (item) => {
break
}
}
/**
* api接口错误处理
* @param {*} error 错误体
* @param {*} name 接口名 非必传如操作时错误提示不需要提示接口名时可不传
* @return Boolean true 存在错误并处理 false无错误
*/
const HandleApiError = (error, name) => {
let result = false
if (error) {
const tip = name ? `${name}错误:` : ``;
uni.$u.toast(`${tip}${error.message}`);
result = true;
}
return result;
}
// 工具类的文件需要把文件提供的工具类统一放最下方做一个统一输出
export {
// async await 标识结果处理
@ -94,6 +85,5 @@ export {
// 防抖函数
Debounce,
// 广告跳转
AdJump,
HandleApiError
AdJump
}

@ -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-06-13 10:15:03
* @Description: file content
*/
import Vue from 'vue';
@ -13,7 +13,6 @@ 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';
@ -31,23 +30,11 @@ const socketInit = () => {
});
}
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() : '';
if(ua.includes('micromessenger')) {

@ -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" : {

@ -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-06-01 15:15:11
* @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">

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-26 14:32:03
* @LastEditors: ch
* @LastEditTime: 2022-06-14 20:48:40
* @LastEditTime: 2022-06-14 12:52:10
* @Description: file content
-->
<template>
@ -27,16 +27,16 @@
<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>
<view class="receive--name">{{item.fromNickname}}</view>
<template v-if="item.type == MSG_TYPE.CUSTOM">
<GoodsInfo class="receive--box" position="msg" v-if="item.payload.id" :goodsInfo="item.payload"/>
<OrderInfo class="receive--box" position="msg" v-if="item.payload.orderId" :orderInfo="item.payload"/>
<view class="receive--box receive--box__txt" v-if="item.payload.customType == 'transferWaiterSession'">{{item.payload.text}}</view>
<template v-else>
<GoodsInfo class="receive--box" position="msg" v-if="item.payload.id" :goodsInfo="item.payload"/>
<OrderInfo class="receive--box" position="msg" v-if="item.payload.orderId" :orderInfo="item.payload"/>
</template>
</template>
<view class="receive--box receive--box__txt" v-if="item.type == MSG_TYPE.TXT">{{item.payload.text}}</view>
@ -84,9 +84,6 @@ export default {
return this.curSessionData ? this.curSessionData.messageList : [];
}
},
destroyed(){
Im.setCurSessionId(null);
},
watch:{
msgData(){
this.$nextTick(()=>{
@ -277,7 +274,6 @@ page{
color: #333;
font-size: 32rpx;
line-height: 40rpx;
word-break: break-all;
}
&__img{
height: 140rpx;
@ -309,7 +305,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-06-12 15:30:00
* @Description: file content
-->
<template>
@ -18,15 +18,12 @@
<text class="msgItem--text" v-if="item.lastMessage">
<template v-if="item.lastMessage.type == msgType.TXT">{{item.lastMessage.payload.content || item.lastMessage.payload.text}}</template>
<template v-if="item.lastMessage.type == msgType.CUSTOM">
<template v-if="item.lastMessage.payload.customType === 'orderAutoDelivery'">
{{item.lastMessage.payload.content}}
</template>
<template v-if="item.lastMessage.payload.customType === 'app_push'">
{{item.lastMessage.payload.link ? '[链接]' : item.lastMessage.payload.content}}
</template>
<template v-if="item.lastMessage.payload.customType === 'transferWaiterSession'">
[客服转移]
</template>
<template v-else>
{{item.lastMessage.payload.content || '[未知消息]'}}
</template>
</template>
<template v-if="item.lastMessage.type == msgType.IMG">[]</template>
<template v-if="item.lastMessage.type == msgType.VIDEO">[]</template>
@ -112,8 +109,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-22 15:09:06
* @LastEditors: ch
* @LastEditTime: 2022-06-23 17:45:29
* @LastEditTime: 2022-06-12 13:46:04
* @Description: file content
-->
<template>
@ -28,7 +28,6 @@ export default {
return this.$store.state.userInfo
}
},
methods:{
logout(){
uni.showModal({

@ -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-06-02 14:39:30
* @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 mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html';
import UiButton from '../../../components/UiButton.vue';
import Comment from './modules/Comment.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弹窗
@ -237,12 +206,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: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-06-22 19:39:05
* @LastEditTime: 2022-06-13 14:25:25
* @Description: file content
-->
<template>
@ -108,7 +108,7 @@ export default {
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_BANNER
});
this.bannerList = result || [];
this.bannerList = result;
},
async getSeckillList(){
const {error, result} = await ApiGetHomeSeckill();

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-23 10:31:12
* @LastEditors: ch
* @LastEditTime: 2022-06-22 19:38:00
* @LastEditTime: 2022-05-31 17:19:26
* @Description: file content
-->
<template>
@ -40,7 +40,7 @@ export default {
props:{
data : {
type : Array,
default : ()=>([])
default : []
}
},
methods:{

@ -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-03-31 14:26:09
* @LastEditors: ch
* @LastEditTime: 2022-06-22 11:22:41
* @LastEditTime: 2022-05-30 17:46:53
* @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>
@ -44,12 +44,12 @@ 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 {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,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,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-06-01 15:34:49
* @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" v-if="orderInfo.orderType !== ORDER_TYPE.VIRTUAL">
<text class="company--name">{{orderInfo.companyName}}</text>
<view class="company--no">
<text>{{orderInfo.trackingNo}}</text>
@ -38,12 +38,12 @@ import UiGoodsInfo from '@/components/UiGoodsInfo.vue'
import UiWhiteBox from '@/components/UiWhiteBox.vue'
import {ApiGetOrderLogistics} from '@/common/api/order';
import UiCopy from '../../components/UiCopy.vue';
import ORDER from '@/common/dicts/order';
import {ORDER_TYPE} from '@/common/dicts/order';
export default {
components: { UiWhiteBox, UiGoodsInfo, UiCopy },
data(){
return {
ORDER,
ORDER_TYPE,
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();
}
}

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

@ -1,35 +0,0 @@
<!--
* @Author: ch
* @Date: 2022-07-12 17:19:59
* @LastEditors: ch
* @LastEditTime: 2022-07-12 18:35:24
* @Description: file content
-->
<template><view>
<web-view :src="url"></web-view>
</view>
</template>
<script>
export default {
data (){
return {
url : ''
}
},
onLoad(){
this.url = decodeURIComponent(this.$Route.query.url);
},
onReady() {
var currentWebview = this.$scope.$getAppWebview() //html5plusplus.webview.currentWebview()uni-appvue使plus.webview.currentWebview()
setTimeout(function() {
let wv = currentWebview.children()[0];
wv.addEventListener('loaded',function() {
console.log('xxxxx',wv.getURL())
console.log(wv.getURL()) //url
console.log(wv.getTitle()) //
}, false);
}, 1000); //
}
}
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

Loading…
Cancel
Save