Compare commits

..

No commits in common. 'main' and 'msb_beta' have entirely different histories.

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

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

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

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

32
.gitignore vendored

@ -1,28 +1,8 @@
.DS_Store
node_modules/
unpackage/
dist/
.history/
.hbuilderx/
.history/
env.js
yarn.lock
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.project
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
node_moudel/
package-lock.json
unpackage/dist/build/.automator/
unpackage/dist/dev
unpackage/cache

@ -1,23 +1,22 @@
<!--
* @Author: ch
* @Date: 2022-05-23 20:13:23
* @Date: 2019-04-01 01:47:12
* @LastEditors: ch
* @LastEditTime: 2022-05-24 10:00:15
* @LastEditTime: 2022-04-30 17:47:26
* @Description: file content
-->
<script>
export default {
onLaunch: function() {
console.log('App Launch')
// console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
// console.log('App Hide')
}
}
</script>
<style lang="scss">
@ -38,4 +37,6 @@
/* 兼容 iOS >= 11.2 */
}
/* #endif */
</style>
</style>

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

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

@ -1,63 +0,0 @@
const plugins = []
if (process.env.UNI_OPT_TREESHAKINGNG) {
plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js'))
}
if (
(
process.env.UNI_PLATFORM === 'app-plus' &&
process.env.UNI_USING_V8
) ||
(
process.env.UNI_PLATFORM === 'h5' &&
process.env.UNI_H5_BROWSER === 'builtin'
)
) {
const path = require('path')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
const input = normalizePath(process.env.UNI_INPUT_DIR)
try {
plugins.push([
require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'),
{
file (file) {
file = normalizePath(file)
if (file.indexOf(input) === 0) {
return path.relative(input, file)
}
return false
}
}
])
} catch (e) {}
}
process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui']
process.UNI_LIBRARIES.forEach(libraryName => {
plugins.push([
'import',
{
'libraryName': libraryName,
'customName': (name) => {
return `${libraryName}/lib/${name}/${name}`
}
}
])
})
module.exports = {
presets: [
[
'@vue/app',
{
modules: 'commonjs',
useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry'
}
]
],
plugins
}

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-17 16:37:45
* @LastEditors: ch
* @LastEditTime: 2022-05-24 17:25:25
* @LastEditTime: 2022-05-16 15:52:57
* @Description: file content
*/
@ -18,7 +18,7 @@ export const ApiPostLogin = (data) => ToAsyncAwait(MsbRequest.post(`${BASE_URL}/
* 退出登录
* @param {*} data
*/
export const ApiGetLogout= () => ToAsyncAwait(MsbRequest.get(`${BASE_URL}/user/logout`));
export const ApiGetLogout= () => ToAsyncAwait(MsbRequest.post(`${BASE_URL}/user/logout`));
/**
* 获取手机验证码
* @param {*} params

@ -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))
/**

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

File diff suppressed because one or more lines are too long

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-10 20:50:54
* @LastEditors: ch
* @LastEditTime: 2022-05-23 14:29:55
* @LastEditTime: 2022-05-13 14:28:29
* @Description: file content
*/
@ -20,30 +20,16 @@ const MSG_TYPE = {
// 提示消息
TIP : 7
}
// 系统会话类型
const SYS_IO = {
// 连接心跳
HEART: 0,
// 获取会话列表
GET_SESSION_LIST: 1,
// 查询会话消息
GET_SESSION_MSG: 2,
// 发送消息
SEND_MSG: 3,
// 根据消息ID查询消息
GET_ID_MSG: 4,
}
const KF_IO = {
// 会话心跳
HEART: 22,
const TYPE = {
// 给某个会话发送消息
SEND_MSG: 20,
// 创建会话
CRETAE_SEEION: 21,
// 会话心跳
SESSION_HEART : 22
}
export {
// 消息类型
MSG_TYPE,
SYS_IO,
KF_IO
MSG_TYPE
}

@ -0,0 +1,85 @@
/**
* 枚举类
* Enum.IMAGE.name => "图片"
* Enum.getNameByKey('IMAGE') => "图片"
* Enum.getValueByKey('IMAGE') => 10
* Enum.getNameByValue(10) => "图片"
* Enum.getData() => [{key: "IMAGE", name: "图片", value: 10}]
*/
class Enum {
constructor (param) {
const keyArr = []
const valueArr = []
if (!Array.isArray(param)) {
throw new Error('param is not an array!')
}
param.map(element => {
if (!element.key || !element.name) {
return
}
// 保存key值组成的数组方便A.getName(name)类型的调用
keyArr.push(element.key)
valueArr.push(element.value)
// 根据key生成不同属性值以便A.B.name类型的调用
this[element.key] = element
if (element.key !== element.value) {
this[element.value] = element
}
})
// 保存源数组
this.data = param
this.keyArr = keyArr
this.valueArr = valueArr
// 防止被修改
// Object.freeze(this)
}
// 根据key得到对象
keyOf (key) {
return this.data[this.keyArr.indexOf(key)]
}
// 根据key得到对象
valueOf (key) {
return this.data[this.valueArr.indexOf(key)]
}
// 根据key获取name值
getNameByKey (key) {
const prop = this.keyOf(key)
if (!prop) {
throw new Error('No enum constant' + key)
}
return prop.name
}
// 根据value获取name值
getNameByValue (value) {
const prop = this.valueOf(value)
if (!prop) {
throw new Error('No enum constant' + value)
}
return prop.name
}
// 根据key获取value值
getValueByKey (key) {
const prop = this.keyOf(key)
if (!prop) {
throw new Error('No enum constant' + key)
}
return prop.key
}
// 返回源数组
getData () {
return this.data
}
}
export default Enum

@ -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();
});
// 全局路由后置守卫

@ -0,0 +1,62 @@
/*
* @Author: ch
* @Date: 2022-03-22 18:28:52
* @LastEditors: ch
* @LastEditTime: 2022-04-29 14:13:05
* @Description: file content
*/
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex);
const
// token
TOKEN = 'tk',
// 用户信息
USER_INFO = 'ui',
// 地址列表
ADDRESS = 'ads',
// oppenId
OPPED_ID = 'oi';
export default new Vuex.Store({
state : {
token : uni.getStorageSync(TOKEN) || '',
userInfo : JSON.parse(uni.getStorageSync(USER_INFO) || '{}'),
address : JSON.parse(uni.getStorageSync(ADDRESS) || '[]'),
sessionData : [],
sessionMsgCount : 0,
sessionMsgId : '',
openId : uni.getStorageSync(OPPED_ID) || ''
},
mutations:{
SET_TOKEN (state, token = ''){
state.token = token;
uni.setStorageSync(TOKEN, token);
},
SET_USER_INFO (state, userInfo = {}){
state.userInfo = userInfo;
uni.setStorageSync(USER_INFO, JSON.stringify(userInfo));
},
SET_ADDRESS (state, address = []){
state.address = address;
uni.setStorageSync(ADDRESS, JSON.stringify(address));
},
SET_SESSION_DATA (state, data){
state.sessionData = data ;
},
SET_SESSION_MSG_COUNT (state, data){
state.sessionMsgCount = data;
},
SET_OPEN_ID (state, data){
state.openId = data;
uni.setStorageSync(OPPED_ID, data);
},
SET_SESSION_MSG_ID (state, data){
state.sessionMsgId = data;
}
},
actions : {
}
})

@ -0,0 +1,18 @@
/*
* @Author: ch
* @Date: 2022-03-22 16:52:28
* @LastEditors: ch
* @LastEditTime: 2022-05-06 21:06:14
* @Description: 所有工具类统一在这输出
*/
import * as util from './utils';
import * as requset from './requset';
import * as websocket from './requset';
import * as wxpay from './wxpay';
export * from './utils';
export * from './requset';
export * from './websocket';
export * from './wxpay';
export default { ...util, ...requset, ...websocket, ...wxpay}

@ -0,0 +1,57 @@
/*
* @Author: ch
* @Date: 2022-05-06 15:33:55
* @LastEditors: ch
* @LastEditTime: 2022-05-06 21:02:39
* @Description: file content
*/
import { ApiPostWxH5Pay, ApiPostWxJsApiPay } from '@/common/api/wx';
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(`https://you-app.mashibing.com/payResult?orderId=${orderId}&payType=wxh5`);
window.location.href = `${result.dataInfo.payUrl}&redirect_url=${redirect_url}`;
}
// #ednif
}

@ -2,21 +2,20 @@
* @Author: ch
* @Date: 2022-03-17 17:42:32
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:39:07
* @LastEditTime: 2022-05-17 18:15:04
* @Description: 项目接口请求统一处理器返回一个需要token和不需要token的请求封装方法
*/
import MsbUniRequest from '@/common/plugins/msbUniRequest';
import $store from '@/common/store';
import { CreateUUID } from '@/common/utils';
const ENV = process.env;
// 获取已有的UUID没则创建一个并保存到locaStorage中下次使用
let uuid = $store.state.uuid
if (!uuid) {
uuid = CreateUUID(16, 2);
$store.commit('SET_UUID', uuid);
}
const ENV = 'prod';
const BASE_URL = {
'test' : 'https://k8s-horse-gateway.mashibing.cn',
'dev' : '',
'release' : '',
'prod' : 'https://you-gateway.mashibing.com'
};
/**
* 接口返回成功结果统一处理
* @param {*} response
@ -82,7 +81,7 @@ const clearRepeat = (option) =>{
// 不需要token的接口封装
const MsbRequest = new MsbUniRequest();
MsbRequest.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequest.baseUrl = BASE_URL[ENV];
MsbRequest.use('request', (option) => {
if(option.header.repeat){
@ -92,7 +91,6 @@ MsbRequest.use('request', (option) => {
return isRepeatVerify;
}
}
option.header.uid = uuid;
return option;
})
MsbRequest.use('success', successIntercept);
@ -102,29 +100,28 @@ MsbRequest.use('error', errorIntercept);
// 需要token的接口封装
const MsbRequestTk = new MsbUniRequest();
MsbRequestTk.baseUrl = ENV.VUE_APP_BASE_URL;
MsbRequestTk.baseUrl = BASE_URL[ENV];
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);

@ -0,0 +1,176 @@
/*
* @Author: ch
* @Date: 2022-03-17 19:15:10
* @LastEditors: ch
* @LastEditTime: 2022-05-07 17:18:50
* @Description: 一些无法归类的公共方法容器
*/
/**
* 处理async await 标识结果处理
*
* @param {*} promise promise对象
* @param {*} isFromatResult 是否处理结果
* @returns {error,result} error有错为错误对象没错为null result正确的返回结果
* isFromatResult 为false时直接返回promise对象不做任何处理
*
*/
const ToAsyncAwait = (promise, isFromatResult = true) => {
if(!isFromatResult){
return promise;
}else{
return promise.then((res) => ({error:null,result:res})).catch((err) => ({error:err,result:null}));
}
}
/**
* 首次运行时把定时器赋值给一个变量 第二次执行时
* 如果间隔没超过定时器设定的时间则会清除掉定时器
* 重新设定定时器 依次反复 当我们停止下来时
* 没有执行清除定时器 超过一定时间后触发回调函数
*/
const Debounce = (fn, delay) => {
let timer
return function() {
const that = this
const _args = arguments // 存一下传入的参数
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
fn.apply(that, _args)
}, delay)
}
}
/**
* 匹配phone
*/
const IsPhone = (str) => /^(1[3-9]\d{9})$/.test(str);
/**
* 判断数值类型包括整数和浮点数
*/
const IsNumber = (str) => (isDouble(str) || isInteger(str)) ? true : false;
/**
* 匹配integer
*/
const IsInteger = (str) => {
if (str == null || str == "") return false
var result = str.match(/^[-\+]?\d+$/)
if (result == null) return false
return true
}
/**
* 匹配double或float
*/
const IsDouble = (str) => {
if (str == null || str == "") return false
var result = str.match(/^[-\+]?\d+(\.\d+)?$/)
if (result == null) return false
return true
}
/**
*
* 时间格式化
* @param {number|string|Date} d 时间参数能被new Date识别的数字字符串日期
* @param {string} fmt 时间格式参数 字符串类型 默认'yyyy/mm/dd'
*/
const formatDate = (date, fmt = 'yyyy/mm/dd' ) =>{
// 处理不识别的时间表示字符串如2020年01月01日00时00分00秒
if(date.constructor === String){
date = date.replace(/\D+/ig,'/');
let arr = date.split('/');
// 长度大于3说明带了时分秒信息 特殊时间处理格式
if(arr.length > 3){
let time = ` ${arr[3]}:${arr[4]}:${arr[5]}`
arr.length = 3;
date = arr.join('/') + time;
}
};
try{
date = date ? date.constructor === Date ? date : new Date(date) : new Date();
} catch(e){
throw new Error('不能识别的时间格式');
}
const o = {
'm+': date.getMonth() + 1, //月份
'd+': date.getDate(), //日
'h+': date.getHours(), //小时
'i+': date.getMinutes(), //分
's+': date.getSeconds(), //秒ji“
'q+': Math.floor((date.getMonth() + 3) / 3), //季度
'l+': date.getMilliseconds() //毫秒
};
if (/(y+)/i.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear().toString()).substr(4 - RegExp.$1.length));
}
for (let k in o) {
if (new RegExp(`(${k})`, 'i').test(fmt)) {
const str = o[k].toString();
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : (`0${str}`).substr(str.length-1));
}
}
return fmt;
}
const createUUID = (len,radix) => {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
let uuid = [],
i=0;
radix = radix || chars.length;
if(len){
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random()*radix];
}else{
let r = 0;
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random()*16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
const toSearchJson = (search)=>{
search = search.replace(/\?/g,'&');
let searchArr = search.split('&'),
obj = {};
searchArr.forEach(i =>{
const me = i.split('=');
if(me[0]){
obj[me[0]] = decodeURIComponent(me[1]);
}
});
return obj;
}
const getPlatform = ()=>{
}
// 工具类的文件需要把文件提供的工具类统一放最下方做一个统一输出
export {
// async await 标识结果处理
ToAsyncAwait,
// 防抖函数
Debounce,
// 判断是否为手机号
IsPhone,
// 判断是否为数字
IsNumber,
// 判断是否为整数
IsInteger,
// 判断是否double或float
IsDouble,
// 时间格式化
formatDate,
createUUID,
toSearchJson
}

@ -0,0 +1,156 @@
/*
* @Author: ch
* @Date: 2022-04-25 14:39:19
* @LastEditors: ch
* @LastEditTime: 2022-05-17 18:14:57
* @Description: file content
*/
import store from "../store";
import {createUUID, formatDate} from '@/common/utils';
let sessionListFlag = false;
const sessionList = (ctx) => {
sessionListFlag = true;
// 来新消息先查会话列表是否一存在,存在则加消息数。不存在则向会话列表加一个会话框
ctx.sessionVOS.forEach(item => {
if (item.lastMessage) {
item.lastMessage.createTimeStamp = formatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii')
item.lastMessage.payload = JSON.parse(item.lastMessage.payload || {});
}
let historyData = store.state.sessionData;
let hisIndex = historyData.findIndex(i => i.id === item.id);
if(hisIndex >= 0){
historyData[hisIndex].lastMessage = item.lastMessage;
historyData[hisIndex].unreadCount++;
store.commit('SET_SESSION_DATA', historyData);
}else{
item.messageList = [];
store.commit('SET_SESSION_DATA',[...historyData, item]);
}
});
// 消息总数
store.commit('SET_SESSION_MSG_COUNT', ctx.totalUnreadCount);
}
const historyMsg = (ctx) => {
if(!ctx.length){
return false;
}
// ctx.reverse();
let newData = store.state.sessionData;
const hisIdx = newData.findIndex(i => i.id === ctx[0].sessionId);
ctx.forEach(item => {
item.createTimeStamp = formatDate(item.createTimeStamp, 'mm-dd hh:ii');
item.payload = JSON.parse(item.payload)
})
// newData[hisIdx].messageList = ctx.concat(newData[hisIdx].messageList);
newData[hisIdx].messageList = newData[hisIdx].messageList.concat(ctx);
store.commit('SET_SESSION_DATA', newData);
}
/**
* 收到某个会话的信息
* @param {*} ctx
*/
const sessionMsg = (ctx)=>{
// 没接到会话列表时接到的消息不做处理
if(!sessionListFlag){
return
}
ctx.payload = JSON.parse(ctx.payload || {});
ctx.createTimeStamp = formatDate(ctx.createTimeStamp || new Date(), 'mm-dd hh:ii')
let historyData = store.state.sessionData;
const hisIndex = historyData.findIndex(i => i.id === ctx.sessionId);
// 不在当前会话框则全局消息加1
if(ctx.sessionId !== store.state.sessionMsgId){
store.commit('SET_SESSION_MSG_COUNT', store.state.sessionMsgCount + 1);
}
if(hisIndex >= 0){
// 存在会话往现有会话增加一条消息
const curHisData = historyData[hisIndex];
// curHisData.messageList = [ ctx, ...(curHisData.messageList || [])]
curHisData.messageList.push(ctx); //= [ ctx, ...(curHisData.messageList || [])]
// 不在当前会话框则会话框消息加1
if(ctx.sessionId !== store.state.sessionMsgId){
curHisData.unreadCount++;
}
store.commit('SET_SESSION_DATA', historyData);
}else{
// 会话列表不存在,则创建一个会话
store.commit('SET_SESSION_DATA',[...historyData, {
fromAvatar : ctx.fromAvatar,
fromId : ctx.fromId,
fromNickname : ctx.fromNickname,
id : ctx.id,
lastMessage : ctx,
messageList : [ctx],
unreadCount : 1
}]);
}
}
// 用户自己创建了一个会话
const createSessionMain = (ctx) => {
let historyData = store.state.sessionData;
const curHis = historyData.find(i => i.id === ctx.id);
store.commit('SET_SESSION_MSG_ID', ctx.id);
if (curHis) {
return false;
}
store.commit('SET_SESSION_DATA',[...historyData, {
...ctx,
unreadCount : 0,
messageList : []
}]);
}
export let MsbWebSkt = null;
const token = 'eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjQwNzA4ODAwMDAsImlkIjo5LCJ0aW1lIjoxNjUyNTAwMDUyNTgwfQ.VAMmJTU1FAcw-vD39E_7EHoDaEdKD3A53L-kdcF6Hj_ygs1urs7xfTNsE2Z_Tb5wXRkS_j-qm0pGnRgfD2EQebc8Pcd28-Rp2W8o-CmCw2_uZUZbfUGeFRZ_ihsFCCpsepU7uEkA9L--cI_u3jw9xdNqzkiXYAVeAXsJ2j570bk'
export const MsbWebSktInit = () => {
return new Promise((resolve, reject) => {
MsbWebSkt = uni.connectSocket({
url : `wss://you-gateway.mashibing.com/ws?client=${store.state.token}&type=1`, // url是websocket连接ip
// url : `wss://k8s-horse-gateway.mashibing.cn/ws?client=${store.state.token}&type=1`, // url是websocket连接ip
// url : `ws://192.168.10.93:8090/ws?client=${token}&type=1`, // url是websocket连接ip
fail: e => {
reject(e)
}
});
MsbWebSkt.onOpen(() => {
MsbWebSkt.onMessage((res) => {
const data = JSON.parse(res.data || {});
if (data.code === 200) {
const ctx = data.content;
switch (data.traceType) {
// 会话列表
case 1:
sessionList(ctx);
break;
// 历史消息
case 2:
case 23:
historyMsg(ctx);
break;
// 创建会话
case 21:
createSessionMain(ctx);
break;
// 会话消息
case 25:
case 20:
case 7:
sessionMsg(ctx)
break;
default:
break;
}
}
})
resolve();
});
MsbWebSkt.onClose(() => {
console.log('断开。。。。。');
})
})
}

@ -2,12 +2,11 @@
* @Author: ch
* @Date: 2022-04-29 14:26:10
* @LastEditors: ch
* @LastEditTime: 2022-07-13 10:40:10
* @LastEditTime: 2022-05-07 17:07:08
* @Description: file content
*/
import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/pay';
const ENV = process.env;
import { ApiPostWxH5Pay, ApiPostWxJsApiPay, ApiPostWxAppPay } from '@/common/api/wx';
export const Wxpay = async ({orderId,openId})=>{
// #ifdef APP-PLUS
@ -16,7 +15,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 +51,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 +73,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(`https://you-app.mashibing.com/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;

@ -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,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-29 16:05:06
* @LastEditors: ch
* @LastEditTime: 2022-05-21 20:04:47
* @LastEditTime: 2022-04-30 15:33:47
* @Description: file content
-->
<template>
@ -14,7 +14,6 @@
</UiCell>
<u-picker
:show="show"
ref="picker"
keyName="name"
:columns="columnsData"
:defaultIndex="defaultIndex"
@ -26,7 +25,7 @@
</template>
<script>
import UiCell from "./UiCell";
import Province from '@/common/dicts/area.json';
import Province from '@/common/dicts/area';
const DefaultCityColumn = Province[0].children;
const DefaultAreaColumn = DefaultCityColumn[0].children;
export default {
@ -83,22 +82,10 @@ export default {
this.columnsData = [Province, DefaultCityColumn, DefaultAreaColumn];
}
},
changeCity(val) {
if(val.columnIndex == 2){
return;
}
let newIndexs = val.indexs;
if(val.columnIndex == 0){
newIndexs[1] = 0;
}
newIndexs[2] = 0;
this.defaultIndex = newIndexs;
changeCity(val, b, c) {
const city = val.value[0].children;
const area = city[newIndexs[1]].children;
this.$refs.picker.setColumnValues(1, city);
this.$refs.picker.setColumnValues(2, area);
const area = val.value[1].children;
this.columnsData = [Province, city, area]
},
confirm(value) {
this.show = false;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-07 17:22:44
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:03
* @LastEditTime: 2022-05-07 19:46:04
* @Description: file content
-->
@ -175,7 +175,7 @@ export default {
}
}
}
::v-deep {
/deep/ {
.goods-item--pirce{
text{
font-size: $font-size-lg;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-31 14:49:33
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:04
* @LastEditTime: 2022-04-22 18:24:57
* @Description: file content
-->
<template>
@ -88,7 +88,7 @@ export default {
}
}
}
::v-deep{
/deep/{
.ui-money{
text{
font-size: $font-size-base;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-22 16:48:11
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:05
* @LastEditTime: 2022-04-22 20:52:22
* @Description: file content
-->
<template>
@ -81,7 +81,7 @@ export default {
margin-left: 60rpx;
}
}
::v-deep{
/deep/{
.ui-money{
text{
font-size: $font-size-base;

@ -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>

@ -0,0 +1,39 @@
/*
* @Author: ch
* @Date: 2022-04-19 16:14:03
* @LastEditors: ch
* @LastEditTime: 2022-04-19 17:20:08
* @Description: file content
*/
import Confirm from '../UiConfirm.vue';
export default {
install (Vue) {
// 创建构造类
const ConfirmConstructor = Vue.extend(Confirm)
const showNextConfirm = function (options) {
// 实例化组件
const instance = new ConfirmConstructor({
el: document.createElement('div')
})
// 处理参数
for (const prop in options) {
instance[prop] = options[prop];
}
// 插入Body
document.body.appendChild(instance.$el)
Vue.nextTick(() => {
instance.show = true
})
}
const confirmFn = (options) => {
return showNextConfirm(options);
}
Vue.prototype.$msb ?
Vue.prototype.$msb.confirm = confirmFn :
Vue.prototype.$msb={confirm : confirmFn }
}
}

@ -0,0 +1,27 @@
<!--
* @Author: ch
* @Date: 2022-05-05 10:57:05
* @LastEditors: ch
* @LastEditTime: 2022-05-05 16:53:23
* @Description: file content
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2021-07-26 23:22:16
* @LastEditors: ch
* @LastEditTime: 2022-06-20 17:38:48
* @LastEditTime: 2022-05-16 09:46:02
* @Description: file content
*/
import Vue from 'vue';
@ -11,39 +11,34 @@ import App from './App';
import {router,RouterMount} from '@/common/router/index.js';
import uView from 'uview-ui';
import store from '@/common/store';
import {FormatSearchJson} from '@/common/utils';
import Confirm from '@/components/mount/index';
import route from 'uview-ui/libs/util/route';
import {toSearchJson} 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';
import {MsbWebSkt, MsbWebSktInit, createUUID} from '@/common/utils';
const socketInit = () => {
if (!store.state.userInfo.id) {
setTimeout(() => {
socketInit();
},10000)
return false;
}
// 初始化IM
ImInit().then(() => {
// 获取到会话列表
Im.getSessionList();
});
}
const getUserInfo = async () => {
const { error, result } = await ApiGetCurrentUser();
if (error) {
uni.$u.toast(error.message);
return false;
}
store.commit('SET_USER_INFO', result);
};
if(store.state.token){
// 进入应用则向IM发起心跳包 以及获取IM会话数据
MsbWebSktInit().then(()=>{
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "1",
content: { sysId : "1"}
})
});
if (store.state.token) {
socketInit();
getUserInfo();
setInterval(()=>{
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "0",
content: { text : "ping"}
})
})
}, 5000);
})
}
@ -52,7 +47,7 @@ if (store.state.token) {
const ua = navigator ? navigator.userAgent.toLowerCase() : '';
if(ua.includes('micromessenger')) {
if(!store.state.openId){
let query = FormatSearchJson(window.location.search)
let query = toSearchJson(window.location.search)
if(query.code){
ApiGetOpenId({
code : query.code
@ -81,6 +76,7 @@ if(ua.includes('micromessenger')) {
Vue.use(router);
Vue.use(uView);
Vue.use(Confirm);
Vue.prototype.$store = store;
Vue.config.productionTip = false;

@ -1,8 +1,8 @@
{
"name" : "马士兵严选",
"appid" : "__UNI__5FEB250",
"appid" : "__UNI__3FB31B6",
"description" : "",
"versionName" : "1.0.1",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
@ -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,11 +118,19 @@
"base" : ""
},
"devServer" : {
"port" : 8080
},
"optimization" : {
"treeShaking" : {
"enable" : true
"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"
}
}
}
}

23183
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,123 +1,27 @@
{
"name": "shop-app",
"version": "0.1.0",
"private": true,
"name": "shopping-app",
"version": "1.0.0",
"description": "严选",
"main": "main.js",
"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",
"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: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",
"build:mp-jd": "cross-env NODE_ENV=production UNI_PLATFORM=mp-jd vue-cli-service uni-build",
"build:mp-kuaishou": "cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
"build:mp-lark": "cross-env NODE_ENV=production UNI_PLATFORM=mp-lark vue-cli-service uni-build",
"build:mp-qq": "cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"build:mp-xhs": "cross-env NODE_ENV=production UNI_PLATFORM=mp-xhs vue-cli-service uni-build",
"build:quickapp-native": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
"build:quickapp-webview": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
"build:quickapp-webview-huawei": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
"build:quickapp-webview-union": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
"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",
"dev:mp-jd": "cross-env NODE_ENV=development UNI_PLATFORM=mp-jd vue-cli-service uni-build --watch",
"dev:mp-kuaishou": "cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch",
"dev:mp-lark": "cross-env NODE_ENV=development UNI_PLATFORM=mp-lark vue-cli-service uni-build --watch",
"dev:mp-qq": "cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"dev:mp-xhs": "cross-env NODE_ENV=development UNI_PLATFORM=mp-xhs vue-cli-service uni-build --watch",
"dev:quickapp-native": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch",
"dev:quickapp-webview": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch",
"dev:quickapp-webview-huawei": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch",
"dev:quickapp-webview-union": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js",
"serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js",
"test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i",
"test:h5": "cross-env UNI_PLATFORM=h5 jest -i",
"test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i",
"test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "http://internel-git.mashibing.cn/chenhui/shopping-app.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@dcloudio/uni-app-plus": "^2.0.1-34720220422002",
"@dcloudio/uni-h5": "^2.0.1-34720220422002",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-360": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-alipay": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-baidu": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-jd": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-kuaishou": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-lark": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-qq": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-toutiao": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-vue": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-weixin": "^2.0.1-34720220422002",
"@dcloudio/uni-mp-xhs": "^2.0.1-34720220422002",
"@dcloudio/uni-quickapp-native": "^2.0.1-34720220422002",
"@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",
"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"
"vuex": "^3.6.2"
},
"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",
"@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",
"mini-types": "*",
"miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0",
"sass": "^1.52.1",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"Android >= 4.4",
"ios >= 9"
],
"uni-app": {
"scripts": {}
"@dcloudio/uni-helper-json": "^1.0.13",
"git-repo-info": "^2.1.1"
}
}

@ -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",
@ -340,15 +283,5 @@
"custom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
}
},
"condition" : { //
"current": 0, //(list )
"list": [
{
"name": "", //
"path": "", //
"query": "" //onLoad
}
]
}
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 14:12:18
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:08
* @LastEditTime: 2022-04-29 23:09:52
* @Description: file content
-->
<template>
@ -126,7 +126,7 @@ page {
left: 30rpx;
width: 670rpx;
}
::v-deep {
/deep/ {
.form--city .ui-cell{
padding: 0 40rpx;
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 14:12:18
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:10
* @LastEditTime: 2022-05-07 19:07:02
* @Description: file content
-->
<template>
@ -160,7 +160,7 @@ page {
left: 30rpx;
width: 670rpx;
}
::v-deep {
/deep/ {
.del-address .ui-cell--title{
color: $color-yellow3;
}

@ -3,13 +3,13 @@
components: { UiCell },: ch
* @Date: 2019-08-22 19:41:20
* @LastEditors: ch
* @LastEditTime: 2022-06-28 16:38:33
* @LastEditTime: 2022-05-17 18:00:28
* @Description: file content
-->
<template>
<view>
<view class="header">
<u-badge class="header--badge" max="99" :value="$store.state.imMsgCount"
<u-badge class="header--badge" max="99" :value="$store.state.sessionMsgCount"
@click="$Router.push('/messageGroup')"></u-badge>
<image class="header--msg" @click="$Router.push('/messageGroup')" src="@/static/account/xx.png" />
</view>
@ -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">
@ -100,8 +95,7 @@ export default {
this.statistic = result;
},
service(){
// uni.$u.toast('');
this.$Router.push('/messageChat');
uni.$u.toast('客服休息中');
}
}
@ -140,10 +134,6 @@ page {
top: 10rpx;
z-index: 99;
border: 1px solid #fff;
/* #ifndef H5 */
top: 90rpx;
/* #endif */
}
&--cell{
border: 0;
@ -218,7 +208,7 @@ page {
border: 0;
}
}
::v-deep{
/deep/{
.header--cell .ui-cell--title{
font-weight: bold;
font-size: $font-size-lg;

@ -0,0 +1,926 @@
<template>
<view class="chat-list" :class="{'loading':!loading,'isInput':isInput==true,'otherInput':otherInput==true}">
<view v-for="(item,index) in msgData" :key="item.id" :id="item.id" :class="{'nowAt':item.messageId == isNowAit}">
<!-- <view v-if="index>0&&item.sendTime - msgList[index-1].sendTime > 300000">
<view class="chat-item-hint">
<view style="background: none;">{{getTime(item.sendTime)}}</view>
</view>
</view> -->
<!-- 接收的消息 -->
<view class="chat-item-l" v-if="item.fromId != userInfo.id">
<view class="head-img">
<image class="head-img" src="@/static/message/xt.png"></image>
</view>
<view>
<view class="group-user-name clamp" v-if="imObject && imObject.type===2">
{{item.fromNickName||item.nickName}}
</view>
<!-- 文字类型消息 -->
<view v-if="item.type == msgType['txt']" class="chat-item-content" :class="{'jump-box':false}">
<!-- 普通文字消息 -->
<view>{{item.ctx}}</view>
</view>
<!-- 图片类型消息 -->
<view v-if="item.type == msgType['img']" class="chat-item-content-voice" >
<img class="des-img" mode='aspectFit' :src="item.ctx" @click="previewImg(item.ctx)">
</img>
</view>
<!-- 视频类型消息 -->
<view v-if="item.type == msgType['video']" class="chat-item-content-video" @click="clickVideo(item)">
<image class="v-icon" src="@/static/im/ship@2x.png" mode=""></image>
<view class="v-bottom">
<image class="v-b-icon" src="@/static/im/xiazai.png"></image>
</view>
</view>
</view>
</view>
<!-- 发送的消息 -->
<view class="chat-item-r" v-else >
<!-- 文字类型消息 -->
<view v-if="item.type == msgType['txt']" class="chat-item-content" :style="{'maxWidth':Width + 'px'}">
<view v-html="getUrl(item.content)"></view>
</view>
<!-- 图片类型消息 -->
<view v-if="item.type == msgType['img']" class="chat-item-content-voice" :style="{'maxWidth':Width + 'px'}">
<image class="des-img" mode='aspectFit' :src="item.ctx" @click="previewImg(item.ctx)">
</image>
</view>
<!-- 视频类型消息 -->
<view v-if="item.type == msgType['video']" class="chat-item-content-video" @click="clickVideo(item)">
<image class="v-icon" src="@/static/im/ship@2x.png" mode=""></image>
<view class="v-bottom">
<image class="v-b-icon" src="@/static/im/xiazai.png"></image>
</view>
</view>
<!-- 头像 -->
<view class="head-img">
<image class="head-img" src="@/static/message/xt.png"></image>
</view>
</view>
<view v-if="item.type === msgType['tips']">
<view class="chat-item-hint">
<view>{{item.ctx}}</view>
</view>
</view>
</view>
<!-- <view class="ait-jump" @click="aitJump"> -->
<view class="ait-jump" v-if="aitMsgId" @click="aitJump">
<image src="@/static/im/aitbtn1.png"></image>
<text>有人@</text>
<image @click.stop="aitMsgId=''" src="@/static/im/aitbtn2.png"></image>
</view>
<!-- <yinrh-menu-popup v-model="popup" :pop-data="menu" dynamic :x="x" :y="y" direction="row" theme="dark"
:placement="place" @tapPopup="tapPopup" /> -->
</view>
</template>
<script>
import {MSG_TYPE} from '@/common/dicts/im';
export default {
props: {
imObject: {
type: Object,
default: () => {}
},
isInput: {
type: Boolean,
default: false
},
otherInput: {
type: Boolean,
default: false
},
unReadCount: {
type: [String, Number],
default: 0
},
identity: {
type: [String, Number],
default: 0
}
},
data() {
return {
msgType : MSG_TYPE,
msgData :[
{id : 1, fromId : 9, type:1, ctx : 'ype 1文本消息 2语音消息 3图片消息 4视频消息 7提示消息'},
{id : 5, fromId : 3, type:1, ctx: 'ype 1文本消息 2语音消息 3图片消息 4视频消息 7提示消息'},
{id : 2, fromId : 9, type:7, ctx: '给你移动了客服'},
{id : 3, fromId : 2, type:3, ctx : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/mall-product/product2bca55bb5c3adb4d02a7a76039d097eewww800-800.jpg'},
{id : 3, fromId : 2, type:3, ctx : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/aitbtn1.png'},
// {id : 4, formId : 9, type:4},
],
Width: '',
userNo: '',
historyParams: {},
msgList: [],
pullLoad: true,
firstPage: true,
loading: true,
popup: false,
aitMsgId: '',
isNowAit: '',
menu: [{
title: '转发'
}, {
title: '撤回'
}, {
title: '收藏'
}, {
title: '复制'
}],
value: false, // menutrue-
place: 'bottom-end',
x: 0,
y: 0,
selectMsg: {},
//
innerAudioContext: {},
//
audioItem: {}
}
},
created() {
// let app = this;
// uni.getSystemInfo({
// success: function(res) {
// app.Width = res.windowWidth - 116;
// app.Height = res.windowHeight;
// }
// });
// app.innerAudioContext = uni.createInnerAudioContext();
// app.innerAudioContext.autoplay = true;
// app.innerAudioContext.onEnded(() => {
// app.stopAudio()
// })
// //
// app.userNo = uni.getStorageSync('loginToken').userNo
// // app.historyParams = {
// // sessionId: app.imObject.sessionId,
// // msgCount: 100,
// // msgId: '',
// // }
// app.firstPage = true;
// app.msgList = [];
// let msgData = this.imDB.where({
// sessionId: app.imObject.sessionId
// }).limit(100).orderBy('messageId', 'desc').get()
// msgData = msgData.reverse()
// if (app.unReadCount > 0 || msgData.length <= 0) {
// app.getHistoryMsg();
// app.$emit('clearUnReadCount')
// } else {
// app.randerList(msgData)
// app.firstPage = false;
// }
//pushlist
},
beforeDestroy() {
this.chatListOnload()
},
computed: {
imDB: function() {
return this.$store.state.imDB;
},
userInfo (){
return this.$store.state.userInfo
}
},
methods: {
aitJump() {
let app = this;
uni.createSelectorQuery().select(".chat-list").boundingClientRect(data => { //
uni.createSelectorQuery().select("#msg" + app.aitMsgId).boundingClientRect((res) => { //
uni.pageScrollTo({
duration: 0, //0uniapp bug
scrollTop: res.top - data.top, //
})
app.isNowAit = app.aitMsgId
app.aitMsgId = ''
}).exec()
}).exec();
},
chatListOnload() {
uni.$off('scoket')
this.innerAudioContext.stop();
// this.msgList = [];
},
reprot(item) {
},
getUrl(str) {
},
fnThrottle(method, delay, duration) {
},
getHistoryMsg() {
},
randerList(list) {
},
getContent(item) {
},
clickVideo(item) {
let app = this;
uni.showModal({
title: '提示',
content: '暂时无法播放视频,是否下载视频文件?',
success: function(res) {
if (res.confirm) {
app.download(item)
}
}
});
},
download(item) {
if (item.isLoading) {
return false;
}
this.downloadFile(item)
},
scrollTop() {
if (this.pullLoad) {
this.getHistoryMsg();
}
},
tapPopup(e) {
},
copy() {
},
deleteMessage() {
},
forwardMsg() {
},
previewImg(logourl) {
let _this = this;
let imgsArray = [];
imgsArray[0] = logourl
uni.previewImage({
current: 0,
urls: imgsArray
});
},
playAudio(item) {
},
stopAudio() {
},
getSize(num) {
},
getTime(time) {
return dateFormat(time, 'yyyy-MM-dd HH:mm')
},
jumpPages(type, id, flag) {
},
delUnReadCount(res) {
let app = this;
delUnReadCount({
sessionId: res.sessionId,
userId: app.userNo,
platform: 2
})
}
}
}
</script>
<script module="test" lang="renderjs">
export default {
mounted() {
window.addEventListener("click", function(e) {
if (e.target.id == 'isa') {
uni.navigateTo({
url: 'pages/open-url/index?src=' + e.target.innerHTML
})
}
});
},
}
</script>
<style lang="scss" scoped>
.chat-item-content {
color: #0062CC;
position: relative;
.file-loading {
width: 22rpx;
height: 22rpx;
position: absolute;
left: -50rpx;
}
.file-fail {
height: 80rpx;
width: 110rpx;
position: absolute;
left: -110rpx;
background: url('@/static/im/fail.png') no-repeat;
background-position-x: 20rpx;
background-position-y: top;
background-size: 50rpx 50rpx;
&::before {
position: absolute;
content: '发送失败';
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: #999999;
width: 200rpx;
top: 52rpx;
}
}
}
.otherInput {
padding-bottom: 500rpx !important;
}
.isInput {
// padding-bottom: 718rpx !important;
}
.loading {
opacity: 0;
}
.chat-list {
padding: 20rpx 32rpx;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
.chat-item-time {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
font-size: 24rpx;
font-family: DIN;
font-weight: 500;
color: #69707F;
margin: 30rpx 0;
}
.chat-item-hint {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
view {
background: #EEEEEE;
border-radius: 25rpx;
padding: 12rpx 42rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
.chat-item-l {
display: flex;
align-items: top;
margin: 20rpx 0;
.head-img {
width: 64rpx;
height: 64rpx;
margin-right: 20rpx;
border-radius: 50%;
}
.group-user-name {
font-size: 28rpx;
color: #999999;
padding-bottom: 12rpx;
max-width: 300rpx;
}
.jump-box {
position: relative;
padding-bottom: 56rpx !important;
}
.chat-item-content {
background: #FFFFFF;
border-radius: 2rpx 16rpx 16rpx 16rpx;
margin-right: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 20rpx 30rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #000000;
display: flex;
align-items: center;
word-break: break-all;
white-space: pre-wrap;
.audio-icon {
width: 24rpx;
height: 32rpx;
}
}
.chat-item-content-video {
width: 287rpx;
height: 161rpx;
background: #DCDCDC;
border-radius: 2rpx 16rpx 16rpx 16rpx;
position: relative;
.v-icon {
position: absolute;
left: 120rpx;
top: 48rpx;
width: 46rpx;
height: 46rpx;
}
.v-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 40rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 2rpx 16rpx 16rpx 16rpx;
.v-b-icon {
position: absolute;
width: 23rpx;
height: 22rpx;
right: 20rpx;
bottom: 9rpx;
}
}
}
.chat-item-content-voice {
display: flex;
align-items: center;
width: auto;
max-width: 400rpx;
height: auto;
// height: 320rpx;
// background: #FB3A4E;
border-radius: 2rpx 2rpx 16rpx 16rpx;
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #333333;
// padding: 30rpx;
.des-img,
.des-video {
// width: 100%;
height: 150rpx;
// margin-right: 15rpx;
}
}
.chat-item-content-datum {
width: 465rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #FFFFFF;
border-radius: 2rpx 16rpx 16rpx 16rpx;
margin-right: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 35rpx 30rpx;
.datum-info {
display: flex;
flex-flow: column;
flex: 1;
.datum-title {
flex: 1;
width: 300rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 32rpx;
line-height: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
}
.datum-size {
margin-top: 15rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
}
.chat-item-content-picture {
display: flex;
align-items: center;
border-radius: 2rpx 16rpx 16rpx 16rpx;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
image {
width: 213rpx;
}
}
}
.chat-item-r {
display: flex;
align-items: top;
justify-content: flex-end;
margin: 20rpx 0;
>.head-img {
margin-left: 20rpx;
}
.head-img {
width: 64rpx;
height: 64rpx;
padding: 0;
border-radius: 50%;
}
.chat-item-content {
background: #FB3A4E;
border-radius: 16rpx 2rpx 16rpx 16rpx;
margin-left: 84rpx;
box-sizing: border-box;
padding: 20rpx 30rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #FFFFFF;
word-break: break-all;
white-space: pre-wrap;
display: flex;
align-items: center;
.audio-icon {
width: 24rpx;
height: 32rpx;
}
}
.chat-item-content-video {
width: 287rpx;
height: 161rpx;
background: #DCDCDC;
border-radius: 16rpx 2rpx 16rpx 16rpx;
position: relative;
.v-icon {
position: absolute;
left: 120rpx;
top: 48rpx;
width: 46rpx;
height: 46rpx;
}
.v-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 40rpx;
background: rgba(0, 0, 0, 0.4);
border-radius: 2rpx 2rpx 16rpx 16rpx;
.v-b-icon {
position: absolute;
width: 23rpx;
height: 22rpx;
right: 20rpx;
bottom: 9rpx;
}
}
}
.chat-item-content-voice {
display: flex;
align-items: center;
justify-content: flex-end;
width: auto;
max-width: 400rpx;
height: auto;
// height: 320rpx;
// background: #FB3A4E;
border-radius: 16rpx 2rpx 16rpx 16rpx;
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #333333;
// padding: 30rpx;
.des-img,
.des-video {
// width: 100%;
height: 150rpx;
// margin-right: 15rpx;
}
}
.chat-item-content-datum {
width: 465rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #FFFFFF;
border-radius: 16rpx 2rpx 16rpx 16rpx;
margin-left: 84rpx;
background-color: #fff;
box-sizing: border-box;
padding: 35rpx 30rpx;
position: relative;
.file-loading {
width: 22rpx;
height: 22rpx;
position: absolute;
left: -50rpx;
}
.file-fail {
height: 80rpx;
width: 110rpx;
position: absolute;
left: -110rpx;
background: url('@/static/im/fail.png') no-repeat;
background-position-x: 15rpx;
background-position-y: top;
background-size: 50rpx 50rpx;
&::before {
position: absolute;
content: '发送失败';
font-size: 20rpx;
font-family: PingFang SC;
font-weight: 400;
color: #999999;
width: 200rpx;
top: 52rpx;
}
}
.datum-info {
display: flex;
flex-flow: column;
flex: 1;
.datum-title {
flex: 1;
width: 300rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 32rpx;
line-height: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
}
.datum-size {
margin-top: 15rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
}
}
.chat-item-content-picture {
display: flex;
align-items: center;
border-radius: 16rpx 2rpx 16rpx 16rpx;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
image {
width: 213rpx;
}
}
}
}
.datum-type {
image {
width: 74rpx;
height: 77rpx;
}
}
.jump-ques {
color: #00CCFF;
}
.voice-mask {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba($color: #000000, $alpha: 0.6);
z-index: 1003;
.vm-box {
width: 617rpx;
height: 514rpx;
background: #FFFFFF;
border-radius: 16rpx;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 40rpx;
.vm-title {
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333333;
margin-bottom: 25rpx;
}
.vm-user {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.vmu-img {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.vmu-txt {
font-size: 30rpx;
font-family: PingFang SC;
font-weight: bold;
color: #333333;
}
}
.vm-msg {
width: 377rpx;
height: 76rpx;
background: #FB3A4E;
border-radius: 2rpx 16rpx 16rpx 16rpx;
display: flex;
align-items: center;
padding-left: 30rpx;
margin-bottom: 20rpx;
.vmm-img {
width: 24rpx;
height: 32rpx;
transform: rotate(180deg);
}
.vmm-txt {
font-size: 28rpx;
font-family: DIN;
font-weight: 500;
color: #F3F5F6;
}
}
.vm-ipt {
width: 537rpx;
height: 68rpx;
background: #F6F6F6;
border-radius: 8rpx;
font-size: 28rpx;
color: #999;
padding-left: 20rpx;
}
.vm-btm {
height: 106rpx;
width: 100%;
position: absolute;
left: 0;
bottom: 0;
display: flex;
border-top: 1rpx solid #F5F6F6;
.vmb-cel,
.vmb-sub {
width: 50%;
height: 100%;
text-align: center;
line-height: 106rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
}
.vmb-cel {
border-right: 1rpx solid #F5F6F6;
}
}
}
}
.chat-item-l {
/deep/.at_span {
&::after {
content: attr(data-name);
color: #FB3A4E;
}
}
}
.chat-item-r {
/deep/.at_span {
&::after {
content: attr(data-name);
color: #ffffff;
}
}
}
.ait-jump {
position: fixed;
right: 0rpx;
bottom: 200rpx;
width: 273rpx;
height: 78rpx;
background: #FFFFFF;
box-shadow: 0rpx 4rpx 30rpx 1rpx rgba(0, 0, 0, 0.06);
border-radius: 100rpx 0rpx 0rpx 100rpx;
z-index: 9999;
display: flex;
align-items: center;
padding: 0 30rpx;
image {
width: 16rpx;
height: 16rpx;
&:nth-child(1) {
margin-right: 20rpx;
}
&:last-child {
margin-left: auto;
}
}
text {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #FB3A4E;
}
}
.nowAt {
animation: isAt 3s 1;
-webkit-animation: isAt 3s 1;
/* Safari 和 Chrome */
}
@keyframes isAt {
0% {
background: #eee;
}
100% {
background: #fff;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-11 11:45:08
* @LastEditors: ch
* @LastEditTime: 2022-06-14 12:55:27
* @LastEditTime: 2022-05-16 20:06:16
* @Description: file content
-->
<template>
@ -12,9 +12,9 @@
<view class="operation">
<textarea class="operation--input" :focus="focus" v-model="msgCtx" @focus="moreShow = false" @click="emojiShow = false"/>
<view class="operation--btns">
<image class="operation--emoji" src="@/static/im/emoji.png" @click="emojiShow = !emojiShow"/>
<image class="operation--emoji" src="@/static/imxx/emoji.png" @click="emojiShow = !emojiShow"/>
<view class="operation--send" v-if="msgCtx.length" @click="send(msgCtx, MSG_TYPE.TXT)"></view>
<image class="operation--more" v-else src="@/static/im/more.png" @click="moreShow = true" />
<image class="operation--more" v-else src="@/static/imxx/more.png" @click="moreShow = true" />
</view>
</view>
<view class="emoji" v-if="emojiShow">
@ -30,14 +30,14 @@
<view class="other" v-if="moreShow">
<u-upload @afterRead="uploadImg" >
<view class="other--btn">
<image class="other--img" src="@/static/im/img.png"/>
<image class="other--img" src="@/static/imxx/img.png"/>
<view>图片</view>
</view>
</u-upload>
<u-upload @afterRead="uploadVideo" compressed accept="video">
<view class="other--btn">
<image class="other--img" src="@/static/im/video.png"/>
<image class="other--img" src="@/static/imxx/video.png"/>
<view>视频</view>
</view>
</u-upload>
@ -45,7 +45,7 @@
</view>
</template>
<script>
import {Im, ToAsyncAwait} from '@/common/utils';
import {MsbWebSkt, createUUID} from '@/common/utils';
import {MSG_TYPE} from '@/common/dicts/im';
import {Request} from '@/common/utils';
import {ApiPutUser} from '@/common/api/account';
@ -64,10 +64,6 @@ export default {
goodsInfo : {
type : Object,
default : () => ({})
},
sessionId : {
type : Number | String,
default : ''
}
},
data(){
@ -119,7 +115,7 @@ export default {
/**
* 统一发送函数
*/
async send(val, type){
send(val, type){
let payload = {};
switch(type){
case MSG_TYPE.CUSTOM :
@ -134,20 +130,19 @@ export default {
break;
}
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : '20',
content: {
toSessionId : this.$store.state.sessionMsgId,
payload : payload,
toId : 1,
type : type
}
})
});
this.msgCtx = '';
const {error, result} = await ToAsyncAwait(Im.sendMsg({
fromId : this.$store.state.userInfo.id,
content: {
toSessionId : this.sessionId,
payload : payload,
toId : 1,
type : type
}
}));
if(error){
uni.$u.toast(error.message);
return false
}
this.focus = false;
this.$nextTick(() => {
this.focus = true;
@ -158,11 +153,11 @@ export default {
this.msgCtx += str;
},
sendGoods(){
this.send({...this.simpleGoods, customType:'goodsInfo'}, MSG_TYPE.CUSTOM);
this.send(this.simpleGoods, MSG_TYPE.CUSTOM);
this.goodsShow = false;
},
sendOrder(){
this.send({...this.simpleOrder, customType : 'orderInfo'}, MSG_TYPE.CUSTOM);
this.send(this.simpleOrder, MSG_TYPE.CUSTOM);
this.orderShow = false;
},
uploadImg(val){

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-13 15:57:31
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:11
* @LastEditTime: 2022-05-14 13:47:05
* @Description: file content
-->
<template>
@ -14,7 +14,7 @@
</view>
<template v-if="position === 'footer'">
<UiButton class="product--btn" size="min" type="gradual" @click="send"></UiButton>
<image class="product--close" src="@/static/im/close.png" @click="close"/>
<image class="product--close" src="@/static/imxx/close.png" @click="close"/>
</template>
</view>
</template>
@ -85,7 +85,7 @@ export default {
right:30rpx;
}
}
::v-deep{
/deep/{
.product--con-price{
text{
color: #FF512B;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-05-14 14:00:14
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:12
* @LastEditTime: 2022-05-14 15:57:30
* @Description: file content
-->
<template>
@ -78,7 +78,7 @@ export default {
margin-top: 26rpx;
}
}
::v-deep{
/deep/{
.order--con-price{
text{
color: #FF512B;

@ -0,0 +1,913 @@
<template>
<!-- -->
<view class="chat-bottom" :style="{'bottom':isInput==true?getKeyHeight()+'px':'0px'}" @touchend='endAudio'>
<view class="bottom-operation">
<view class="goVoice" @click="setAudioShow">
<image src="../../../static/im/voice.png" mode=""></image>
</view>
<!-- <u-input type="textarea" maxlength="300" :clearable="false" height="80rpx" v-model="chatInfo" placeholder-style="color:#999;" placeholder="输入文字..." /> -->
<textarea v-if="!isIos()&&!audioShow" class="textarea" :class="{'textarea2':chatInfo}" maxlength="300"
v-model="chatInfo" @focus='onInput' placeholder-style="color:#999;" placeholder="输入文字..."
:auto-height='true' :adjust-position="false" />
<textarea v-if="isIos()&&!audioShow" class="textarea" :class="{'textarea2':chatInfo}" maxlength="300"
v-model="chatInfo" @focus='onInput' placeholder-style="color:#999;" placeholder="输入文字..."
:auto-height='true' />
<!-- <view class="textarea" v-if="audioShow"></view> -->
<view class="goexpression" @click="setEmojiShow">
<image src="../../../static/im/expression.png" mode=""></image>
</view>
<view v-show="chatInfo" class="send-btn" @touchend.prevent="sendMsg">
发送
</view>
<view class="more" v-show="!chatInfo" @click="setMoreShow">
<image src="../../../static/im/more.png" mode=""></image>
</view>
</view>
<view class="bottom-box">
<view v-show="emojiShow" class="emoji-box">
<view class="tools-box">
<text class="emoji" @click="setEmoji(item)"
v-for="(item,index) in getEmoji()">{{entitiestoUtf16(item)}}</text>
</view>
</view>
<view v-show="moreShow" class="operation-box">
<view class="operation-item" @click="goQuick">
<view class="item-btn">
<image src="../../../static/im/reply.png" mode=""></image>
</view>
<view class="item-hint">回复</view>
</view>
<view class="operation-item" @click="chooseImage">
<view class="item-btn">
<image src="../../../static/im/picture.png" mode=""></image>
</view>
<view class="item-hint">相册</view>
</view>
<view class="operation-item" @click="chooseFile">
<view class="item-btn">
<image src="../../../static/im/file.png" mode=""></image>
</view>
<view class="item-hint">文件</view>
</view>
<view class="operation-item" @click="chatCollect">
<view class="item-btn">
<image src="../../../static/im/collect.png"></image>
</view>
<view class="item-hint">收藏</view>
</view>
</view>
</view>
<u-popup v-model="showAitFlag" mode="bottom" border-radius="16" >
<!-- -->
<view class="ait-box" :style="{'height':isInput==true? (425 - keyHeight/2) +'px':'425px'}">
<view class="ab-title" >
<u-icon class='abt-close' name="arrow-down" color="#333333" size="24"></u-icon>
<text class="abt-txt">选择提醒的人</text>
</view>
<view class="ipt-wrp">
<image class="ipt-icon" src="@/static/sousuo.png"></image>
<input type="text" confirm-type="search" v-model="aitKeyword" class="ipt" placeholder="昵称搜索" >
</view>
<view class="ab-item" @click="setAit()">
<view class="abi-all">@</view>
<view class="abi-name">@所有人({{groupPeoList.length}})</view>
</view>
<view class="ab-item" @click="setAit(item)" v-for="(item,index) in groupPeoList" v-if="item.nickName.includes(aitKeyword)">
<image class="abi-img" :src="item.avatar"></image>
<view class="abi-name clamp">{{item.nickName}}</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import {
utf16toEntities,
entitiestoUtf16
} from '@/common/js/utils.js'
import emojiData from '@/common/js/emoji.js'
import {
sendMsg,
sendGroupMsg,
sendSpecialMessage,
sendTextMsg,
getUserByGroupId
} from '@/common/api-request/im.js'
import cCircle from "@/components/Your_Exios-Circle/Your_Exios-Circle.vue"
import api from '@/common/js/api.js'
const baseUrl = api.host['local'];
export default {
components: {
cCircle
},
props: {
toUserNo: {
type: [String, Number],
default: ''
},
sendType: {
type: [String, Number],
default: ''
},
isInput: {
type: Boolean,
default: false
},
keyHeight: {
type: Number,
default: 0
},
isScreen: {
type: Boolean,
default: false
}
},
data() {
return {
chatInfo: '',
userNo: '',
moreShow: false,
emojiShow: false,
audioShow: false,
showAitFlag: false,
groupPeoList: [],
recorderManager: {}, //
innerAudioContext: {}, //
voicePath: [], //
timer: null, //
audioText: '长按录音',
audioStart: false,
sendFlag: true, //
voiceCel: false,
stamp: 0, //
txtIndex: 0, //
aitKeyword: '',
isserchinput:false
};
},
created() {
let app = this;
app.userNo = uni.getStorageSync('loginToken').userNo
//
app.recorderManager = uni.getRecorderManager();
console.log('录音对象', app.recorderManager)
app.innerAudioContext = uni.createInnerAudioContext();
app.innerAudioContext.autoplay = true;
app.recorderManager.onStop(function(res) {
console.log('-------停止录音', res)
let now = new Date().getTime()
let obj = {
path: res.tempFilePath,
duration: parseInt((now - app.stamp) / 100) * 100
}
if (obj.duration < 1000) {
uni.showToast({
icon: 'none',
title: '录音太短了!'
})
setTimeout(() => {
app.cancelAudio()
}, 200)
} else {
//
if (!app.voiceCel) {
app.voicePath.push(obj);
app.sendAudio()
}
}
});
if (app.sendType === 2) {
getUserByGroupId(app.toUserNo).then(res => {
console.log('--------------获取群成员', res.data)
app.groupPeoList = res.data
app.groupPeoList.forEach((el, idx) => {
if (el.userNo == app.userNo) {
app.groupPeoList.splice(idx, 1)
}
})
})
}
},
beforeDestroy() {
let app = this;
if (app.innerAudioContext.stop) {
app.innerAudioContext.stop()
}
if (app.timer) {
clearInterval(app.timer)
app.timer = null;
}
},
onShow() {
},
methods: {
getserchInput(){
//
uni.onKeyboardHeightChange(res => {
if (res.height > 0) {
console.log(res.height,'禁停')
// app.keyHeight = res.height
// app.isInput = true;
} else {
// app.isInput = false;
}
})
},
setAit(item) {
let app = this;
app.showAitFlag = false;
//,便
let curEnd = app.chatInfo.slice(app.txtIndex)
let curStr = app.chatInfo.slice(0, app.txtIndex)
if (item) {
app.chatInfo = curStr + item.nickName + '\t' + curEnd
} else {
app.chatInfo = curStr + '所有人' + '\t' + curEnd
}
console.log(item)
},
//
getKeyHeight() {
// if (this.isIos()) {
// if (this.isScreen) {
// return (this.keyHeight - 35)
// } else {
// return (this.keyHeight - 5)
// }
// } else {
// // return this.keyHeight
// return 0
// }
return 0
},
async sendMsg() {
let app = this;
let ids = []
let isAt = false;
if (app.sendType === 2) {
//@\t
let reg = /@.*?\\t/gi;
let result = JSON.stringify(app.chatInfo).match(reg)
if (result) {
for (let i = 0; i < result.length; i++) {
let el = result[i];
let cur = el.slice(1, el.length - 2)
if (cur == '所有人') {
app.groupPeoList.forEach(val => {
ids.push(val.userNo)
})
break;
} else {
app.groupPeoList.forEach(val => {
if (val.nickName == cur) {
ids.push(val.userNo)
}
})
}
console.log(cur)
}
}
isAt = ids.length > 0 ? true : false;
}
if (!app.sendFlag) {
return false;
}
app.sendFlag = false;
let res;
if (!app.chatInfo) {
uni.showToast({
icon: 'none',
title: "请输入聊天内容!"
})
app.sendFlag = true;
return false;
}
if (app.sendType === 1) {
//
res = await sendTextMsg({
content: app.chatInfo,
fromUserNo: app.userNo,
toUserNo: app.toUserNo
})
} else {
//
res = await sendTextMsg({
content: app.chatInfo,
fromUserNo: app.userNo,
groupId: app.toUserNo,
atUsers: ids,
isAt: isAt
})
}
if (res.code === 200) {
app.chatInfo = '';
uni.$emit('scoket', JSON.stringify(res.data))
// app.audioShow = false;
// app.moreShow = false;
// app.emojiShow = false;
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
}
app.sendFlag = true;
},
chooseImage() {
let app = this;
uni.chooseImage({
count: 1, //9
sizeType: ['original', 'compressed'], //
sourceType: ['album', 'camera'], //
success: function(res) {
console.log(res.tempFilePaths[0]);
let filePath = res.tempFilePaths[0]
app.uploadFile(filePath, 1)
}
});
},
chooseFile() {
let app = this;
if (this.isIos()) {
const iOSFileSelect = uni.requireNativePlugin('YangChuan-YCiOSFileSelect');
let params = {
"document-types": ["public.text", "public.zip", "public.movie", "public.data", "com.adobe.pdf",
"com.microsoft.word.doc", "com.adobe.postscript", "com.microsoft.excel.xls",
"com.adobe.encapsulated- postscript", "com.microsoft.powerpoint.ppt",
"com.adobe.photoshop- image", "com.microsoft.word.rtf",
"com.microsoft.advanced- systems-format", "com.microsoft.advanced- stream-redirector"
],
"isBase64": 0
}
iOSFileSelect.show(params, result => {
let filePath = result.url
console.log(result,'result')
let fileName = result.lastName
let fileSize = result.version
app.uploadFile(filePath, 4,fileName,fileSize)
})
} else {
const plugin = uni.requireNativePlugin('GuoWei-SelectFileModule')
plugin.chooseFile({
count: 1
},
result => {
let filePath = result.files[0].url
let fileName = result.files[0].name
let fileSize = result.files[0].size
console.log('-----im文件选择', result)
app.uploadFile(filePath, 4, fileName, fileSize)
}
)
}
},
startAudio() {
console.log('开始录音', this.recorderManager);
let app = this
clearInterval(app.timer)
app.timer = null;
app.stamp = new Date().getTime()
uni.vibrateShort({
success: function() {
console.log('开始录音2', this.recorderManager);
app.timer = setInterval(() => {
uni.showToast({
icon: 'none',
title: '录音时间过长!'
})
app.endAudio()
app.$emit('longStop')
}, 60000)
console.log('开始录音3', this.recorderManager);
app.recorderManager.start();
app.audioText = '松开停止'
}
});
},
endAudio(val = false) {
let app = this;
app.voiceCel = val;
if (app.timer) {
console.log('录音结束');
clearInterval(app.timer)
app.timer = null;
app.recorderManager.stop();
app.audioText = '点击播放'
}
},
playVoice() {
console.log('播放录音');
// console.log('this.voicePath', this.voicePath, this.audioStart);
if (!this.audioStart) {
this.audioStart = true
this.innerAudioContext.src = this.voicePath[0];
this.innerAudioContext.play();
this.audioText = '暂停播放'
} else if (this.audioStart) {
this.audioStart = false
this.innerAudioContext.stop()
this.audioText = '点击播放'
}
},
cancelAudio() {
let app = this;
// app.audioShow = false;
app.moreShow = false;
app.emojiShow = false;
app.timer = null;
app.innerAudioContext.stop()
app.voicePath.length > 0 ? app.voicePath.shift() : app.voicePath = []
app.audioStart = false;
app.audioText = '长按录音'
},
sendAudio() {
let app = this;
if (app.voicePath.length == 1) {
app.uploadFile(app.voicePath[0].path, 2)
}
},
uploadFile(filePath, type, fileName = '', fileSize = 0) {
let header = {}
let app = this;
if (uni.getStorageSync('loginToken')) {
let token = uni.getStorageSync('loginToken');
header['Authorization'] = token.tokenHead + token.token;
header['R-Authorization'] = token.tokenHead + token.refreshToken;
// header['Content-Type'] = 'multipart/form-data'
}
let scoketParams = {
isLoading: 'load',
fromUserNo: app.userNo,
toUserNo: app.sendType == 1 ? app.toUserNo : '',
groupId: app.sendType == 2 ? app.toUserNo : '',
type: type,
fileName: fileName,
fileSize: fileSize,
filePath: filePath,
audioSeconds: app.voicePath && app.voicePath.length > 0 ? app.voicePath[0].duration : ''
}
console.log('ios',scoketParams)
uni.$emit('scoket', JSON.stringify(scoketParams))
uni.uploadFile({
url: baseUrl + '/edu-im/file/upload',
filePath: filePath,
header: header,
name: "file",
success: function(res) {
let resData = JSON.parse(res.data).data
let params = {
content: resData.content,
fileName: resData.filename,
size: resData.size,
fromUserNo: app.userNo,
toUserNo: app.sendType == 1 ? app.toUserNo : '',
groupId: app.sendType == 2 ? app.toUserNo : '',
type: type,
audioSeconds: app.voicePath && app.voicePath.length > 0 ? app.voicePath[0]
.duration : ''
}
sendSpecialMessage(params).then(ret => {
console.log('ret', ret)
if (ret.code === 200) {
console.log('-----------------im发送图片', ret)
app.chatInfo = '';
uni.$emit('scoket', JSON.stringify(ret.data))
app.innerAudioContext.stop()
// app.audioShow = false;
app.moreShow = false;
app.emojiShow = false;
app.audioStart = false;
app.audioText = '长按录音'
if (app.voicePath.length > 1) {
app.voicePath.shift()
setTimeout(() => {
app.sendAudio()
}, 1000)
} else {
app.voicePath = []
}
} else {
uni.showToast({
icon: 'none',
title: ret.msg
})
}
})
},
fail: function(error) {
// uni.showToast({
// title: "", //
// duration: 3000, //
// icon: "none", //"success""loading"
// });
scoketParams.isLoading = 'fail'
uni.$emit('scoket', JSON.stringify(scoketParams))
}
})
},
chatCollect() {
uni.navigateTo({
url: '/pages/im/chat/chatCollect'
})
},
goQuick() {
uni.navigateTo({
url: '/pages/im/quick/index?sendType=' + this.sendType + '&toUserNo=' + this.toUserNo
})
},
getEmoji() {
return [...emojiData[0].list, ...emojiData[1].list, ...emojiData[4].list]
},
setEmoji(data) {
let str = ' ' + this.entitiestoUtf16(data) + ' '
this.chatInfo += str;
},
onInput() {
this.emojiShow = false;
this.audioShow = false;
this.moreShow = false;
this.$emit('setInput', false)
},
setMoreShow() {
this.moreShow = !this.moreShow;
this.emojiShow = false;
this.audioShow = false;
this.$emit('setInput', this.moreShow)
},
setAudioShow() {
this.audioShow = !this.audioShow;
this.emojiShow = false;
this.moreShow = false;
this.$emit('setInput', false)
// this.$emit('setInput', this.audioShow)
},
setEmojiShow() {
// this.chatInfo = '@\t@asdadad1\t2 '
// console.log(JSON.stringify(this.chatInfo))
// return false;
this.emojiShow = !this.emojiShow;
this.moreShow = false;
this.audioShow = false;
this.$emit('setInput', this.emojiShow)
},
utf16toEntities(val) {
return utf16toEntities(val)
},
entitiestoUtf16(val) {
return entitiestoUtf16(val)
},
},
watch: {
audioShow: function(n, o) {
this.$emit('onAudioShow', n)
},
chatInfo: function(n, o) {
let app = this;
if (app.sendType != 2) {
return false;
}
//
uni.getSelectedTextRange({
success: res => {
app.txtIndex = res.end;
//,便
let curEnd = n.slice(res.end)
let curStr = n.slice(0, res.end)
/*
新增艾特相关
*/
let oldStr1 = o.slice(0, res.end)
if (curStr == oldStr1 + '@') {
app.aitKeyword = '';
app.showAitFlag = true;
uni.hideKeyboard()
}
/*
删除艾特相关
*/
//
let oldStr = o.slice(0, res.end + 1)
//\t,
if (curStr.length < oldStr.length && curStr + '\t' == oldStr) {
//
let num = curStr.lastIndexOf('@')
let nowStr = curStr.slice(0, num)
app.chatInfo = nowStr + curEnd;
console.log('删除艾特')
}
}
})
}
}
}
</script>
<style lang="scss">
// .isInput {
// bottom: 570rpx !important;
// }
.chat-bottom {
position: fixed;
bottom: 0;
width: 100%;
min-height: 148rpx;
background-color: #fff;
display: flex;
flex-flow: column;
.bottom-operation {
width: 100%;
display: flex;
align-items: flex-end;
padding: 17px 30rpx;
}
.goVoice {
width: 52rpx;
height: 52rpx;
margin-right: 10rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.textarea {
height: 80rpx;
max-height: 200rpx !important;
overflow: auto;
width: 490rpx;
line-height: 80rpx;
background: #F8F8F8;
border-radius: 40rpx;
padding: 0 40rpx;
}
.textarea2 {
width: 420rpx;
line-height: 48rpx;
min-height: 80rpx;
/deep/.uni-textarea-textarea{
padding-top: 16rpx;
}
}
.audio {
flex: 1;
background: #F8F8F8;
border-radius: 39rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333;
height: 78rpx;
text-align: center;
line-height: 78rpx;
}
/deep/.u-input {
flex: 1;
background: #F8F8F8;
border-radius: 39rpx;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
color: #333;
max-height: 200rpx !important;
overflow-y: auto;
.u-input__textarea {
display: flex;
align-items: center;
box-sizing: border-box;
padding: 20rpx 40rpx;
max-height: 200rpx;
}
}
.goexpression {
width: 52rpx;
height: 53rpx;
margin-left: 15rpx;
margin-right: 19rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.more {
width: 53rpx;
height: 53rpx;
margin-bottom: 15rpx;
image {
width: 100%;
height: 100%;
}
}
.send-btn {
display: flex;
align-items: center;
justify-content: center;
width: 120rpx;
height: 60rpx;
background-color: #fb3a4e;
color: #fff;
font-size: 28rpx;
border-radius: 10rpx;
margin-bottom: 15rpx;
transition: all .3s;
}
.operation-box {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-around;
background-color: #f8f8f8;
padding: 0 30rpx;
.operation-item {
width: 120rpx;
padding: 30rpx 0;
.item-btn {
display: flex;
align-items: center;
justify-content: center;
width: 120rpx;
height: 120rpx;
background-color: #fff;
border-radius: 16rpx;
image {
width: 50rpx;
height: 50rpx;
}
}
.item-hint {
text-align: center;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: 500;
color: #999999;
margin-top: 13rpx;
}
}
}
}
.bottom-box {
max-height: 300rpx;
overflow-y: auto;
}
.emoji-box {
padding: 0 30rpx 30rpx;
.emoji {
margin: 10rpx;
font-size: 48rpx;
}
}
.audio-box {
height: 300rpx;
display: flex;
justify-content: center;
align-items: center;
.circle {
margin: 0 100rpx;
width: 150rpx;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.audio-icon {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-bottom: 20rpx;
}
}
}
.ait-box {
width: 750rpx;
height: 850rpx;
background-color: #fff;
z-index: 999;
.ab-title {
position: relative;
display: flex;
justify-content: center;
align-items: center;
margin-top: 40rpx;
.abt-close {
position: absolute;
top: 10rpx;
left: 40rpx;
}
.abt-txt {
font-size: 28rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
}
.ab-item {
width: 750rpx;
height: 120rpx;
display: flex;
padding: 0 40rpx;
align-items: center;
&:hover {
background-color: #EEEEEE;
}
.abi-all {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 30rpx;
background-color: #FFEBED;
text-align: center;
line-height: 80rpx;
font-size: 36rpx;
font-family: SF Pro Display-Medium, SF Pro Display;
font-weight: 500;
color: #FB3A4E;
}
.abi-img {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 30rpx;
}
.abi-name {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
}
}
}
.ipt-wrp {
margin: 18rpx auto;
position: relative;
width: 690rpx;
.ipt-icon {
position: absolute;
left: 28rpx;
height: 24rpx;
width: 24rpx;
top: 20rpx;
}
.ipt {
width: 100%;
height: 64rpx;
background: #f6f6f6;
border-radius: 32rpx;
font-size: 28rpx;
color: #999;
padding-left: 76rpx;
}
}
</style>

@ -2,16 +2,13 @@
* @Author: ch
* @Date: 2022-03-26 14:32:03
* @LastEditors: ch
* @LastEditTime: 2022-06-14 20:48:40
* @LastEditTime: 2022-05-17 16:22:51
* @Description: file content
-->
<template>
<view class="main">
<template v-for="item in msgData">
<view class="send" :key="item.id" v-if="item.fromId == $store.state.userInfo.id">
<text class="send--status" v-if="item.sendStatus === 'loading'"></text>
<text class="send--status send--status__fail" v-if="item.sendStatus === 'fail'" @click="resend(item)"></text>
<template v-if="item.type == MSG_TYPE.CUSTOM">
<GoodsInfo class="send--box" position="msg" v-if="item.payload.id" :goodsInfo="item.payload"/>
<OrderInfo class="send--box" position="msg" v-if="item.payload.orderId" :orderInfo="item.payload"/>
@ -22,16 +19,13 @@
<view class="send--box" v-if="item.type == MSG_TYPE.VIDEO">
<video class="send--box__video" :src="item.payload.url"></video>
</view>
<image class="avatar" :src="$store.state.userInfo.avatar || require('@/static/message/xt.png')" mode="widthFix"/>
<image class="avatar" :src="item.fromAvatar || '@/static/message/xt.png'" mode="widthFix"/>
</view>
<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"/>
<image class="avatar" :src="item.fromAvatar || '@/static/message/xt.png'" mode="widthFix"/>
<view>
<view class="receive--name">{{item.fromNickname}}</view>
<template v-if="item.type == MSG_TYPE.CUSTOM">
@ -48,18 +42,18 @@
</view>
</view>
</template>
<Footer :goodsInfo="goodsInfo" :orderInfo="orderInfo" :sessionId="sessionId"></Footer>
<Footer :goodsInfo="goodsInfo" :orderInfo="orderInfo"></Footer>
</view>
</template>
<script>
import {MSG_TYPE} from '@/common/dicts/im';
import {Im, ToAsyncAwait} from '@/common/utils';
import {MsbWebSkt, createUUID} from '@/common/utils';
import {ApiGetOrderDetail} from '@/common/api/order';
import {ApiGetGoodsDetail} from '@/common/api/goods';
import UiButton from '@/components/UiButton.vue';
import Footer from './modules/Footer.vue';
import GoodsInfo from './modules/GoodsInfo.vue';
import OrderInfo from './modules/OrderInfo.vue';
import Footer from './components/Footer.vue';
import GoodsInfo from './components/GoodsInfo.vue';
import OrderInfo from './components/OrderInfo.vue';
export default {
components: { UiButton, Footer, GoodsInfo, OrderInfo },
data(){
@ -74,19 +68,14 @@ export default {
},
computed:{
curSessionData(){
const data = this.$store.state.imData.find(i => i.id == this.sessionId) || {};
if(data.id){
Im.setCurSessionId(data.id);
}
return data;
return this.$store.state.sessionData.find(i =>i.id == this.$store.state.sessionMsgId) || {}
},
msgData (){
return this.curSessionData ? this.curSessionData.messageList : [];
}
},
destroyed(){
Im.setCurSessionId(null);
},
watch:{
msgData(){
this.$nextTick(()=>{
@ -110,105 +99,104 @@ export default {
this.$Router.push('/login');
return false;
}
this.goodsId = this.$Route.query.goodsId;
this.orderId = this.$Route.query.orderId;
this.sessionId = this.$Route.query.sessionId;
this.socketInit();
if(this.goodsId){
this.createSessionMain();
this.getGoodsInfo();
}
if(this.orderId){
}else if(this.orderId){
this.createSessionMain();
this.getOrderInfo();
}else if(this.sessionId){
this.$store.commit('SET_SESSION_MSG_ID',this.sessionId);
this.getHistoryMsg();
this.readMsg();
this.heartMsg();
}else{
this.createSessionMain();
}
this.$nextTick(()=>{
uni.pageScrollTo({
scrollTop : 99999,
duration : 0
});
})
},
methods:{
socketInit(){
if(!Im.isOpen){
setTimeout(()=>{
this.socketInit();
}, 100)
return false;
}
if(this.sessionId){
if(!this.msgData?.length){
this.getHistoryMsg();
}
this.readMsg();
}else{
this.createSessionMain();
}
},
/**
* 创建会话主体
* 如果是从商品或订单进来需要创建会话
*/
async createSessionMain(){
if(!Im.isOpen){
setTimeout(()=>this.createSessionMain(),1000);
return false;
}
const {error, result} = await ToAsyncAwait(Im.createSession({
content : {
sessionType : 3
}
}));
if(error){
uni.$u.toast(error.message);
return false;
}
this.sessionId = result.content.id;
Im.setCurSessionId(this.sessionId);
this.getHistoryMsg();
// this.readMsg();
createSessionMain(){
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : '21',
content : {
storeId : 1
}
}),
success:()=>{
//
setTimeout(()=>{
this.getHistoryMsg();
this.readMsg();
this.heartMsg();
},1000)
}
});
},
/**
* 发送心跳
*/
heartMsg(){
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : '22',
content : {
storeId : 1
}
}),
complete: () =>{
setTimeout(()=>{
this.heartMsg();
},5000)
}
})
},
/**
* 获取历史消息
*/
async getHistoryMsg(){
if(!this.curSessionData.id){
setTimeout(()=>{
this.getHistoryMsg();
}, 500)
return false;
}
getHistoryMsg(){
this.loading = true;
const {error, result} = await ToAsyncAwait(Im.getHistoryMsg());
if(error){
uni.$u.toast(error.errMsg || error.message);
return false
}
this.loading = false;
const lastMsg = this.msgData?.length ? this.msgData[0] : {};
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "23",
content: {
sessionId : this.$store.state.sessionMsgId,
topMessageId : lastMsg.id || null
}
})
})
},
/**
* 把当前会话消息置为已读
* 已读消息
*/
async readMsg(){
const {error, result} = await ToAsyncAwait(Im.setRead({
content: {
sessionId : this.sessionId
}
}));
if(error){
uni.$u.toast(error.errMsg || error.message);
console.log(error);
return false
}
},
resend(item){
Im.resend(item)
readMsg(){
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "6",
content: {
sessionId : this.$store.state.sessionMsgId
}
})
});
//
const count = this.$store.state.sessionMsgCount - this.curSessionData.unreadCount;
//
this.curSessionData.unreadCount = 0;
this.$store.commit('SET_SESSION_MSG_COUNT', count)
},
/**
* 从订单页进来查询订单信息
@ -277,7 +265,6 @@ page{
color: #333;
font-size: 32rpx;
line-height: 40rpx;
word-break: break-all;
}
&__img{
height: 140rpx;
@ -288,19 +275,8 @@ page{
display: flex;
justify-content: flex-end;
margin-top:30rpx ;
&--status{
font-size: $font-size-sm;
color: $color-grey3;
display: flex;
align-items: center;
line-height: 46rpx;
margin-right: 10rpx;
&__fail{
color: $color-yellow4;
}
}
&--box{
max-width: 480rpx;
max-width: 552rpx;
margin-right:30rpx;
&__txt{
padding: 20rpx 30rpx;
@ -309,7 +285,6 @@ page{
color: #fff;
font-size: 32rpx;
line-height: 46rpx;
word-break: break-all;
}
&__img{
height: 140rpx;

@ -2,38 +2,28 @@
* @Author: ch
* @Date: 2022-03-22 16:13:00
* @LastEditors: ch
* @LastEditTime: 2022-06-17 16:31:20
* @LastEditTime: 2022-05-14 16:32:09
* @Description: file content
-->
<template>
<view >
<BsEmpty tips="暂时还没有消息哦~" v-if="!sessionData.length"
<BsEmpty tips="暂时还没有消息哦~" v-if="!$store.state.sessionData.length"
:icon="require('@/static/message/empty.png')" />
<view class="msgItem" v-for="item in sessionData" :key="item.id"
<view class="msgItem" v-for="item in $store.state.sessionData" :key="item.id"
@click="openMsg(item)">
<image class="msgItem--headImg" :src="item.fromAvatar || require('@/static/message/xt.png')"></image>
<image class="msgItem--headImg" src="@/static/account/tx.png"></image>
<view class="msgItem--con">
<view>
<text class="msgItem--title">{{item.fromNickname}}</text>
<text class="msgItem--text" v-if="item.lastMessage">
<template v-if="item.lastMessage.type == msgType.TXT">{{item.lastMessage.payload.content || item.lastMessage.payload.text}}</template>
<template v-if="item.lastMessage.type == msgType.CUSTOM">
<template v-if="item.lastMessage.payload.customType === 'app_push'">
{{item.lastMessage.payload.link ? '[链接]' : item.lastMessage.payload.content}}
</template>
<template v-if="item.lastMessage.payload.customType === 'transferWaiterSession'">
[客服转移]
</template>
<template v-else>
{{item.lastMessage.payload.content || '[未知消息]'}}
</template>
</template>
<template v-if="item.lastMessage.type == msgType.CUSTOM">[]</template>
<template v-if="item.lastMessage.type == msgType.IMG">[]</template>
<template v-if="item.lastMessage.type == msgType.VIDEO">[]</template>
</text>
</view>
<view class="msgItem--right">
<text class="msgItem--time" v-if="item.lastMessage">{{FormatDate(item.lastMessage.createTimeStamp, 'mm-dd hh:ii:ss')}}</text>
<text class="msgItem--time" v-if="item.lastMessage">{{item.lastMessage.createTimeStamp}}</text>
<u-badge class="msgItem--badge" :value="item.unreadCount"></u-badge>
</view>
</view>
@ -43,13 +33,12 @@
<script>
import BsEmpty from '../../../components/BsEmpty.vue';
import {MSG_TYPE} from '@/common/dicts/im';
import {FormatDate, Im} from '@/common/utils';
export default {
components: { BsEmpty },
data (){
return {
msgType : MSG_TYPE,
sessionData : this.$store.state.sessionData
}
},
onShow(){
@ -57,22 +46,15 @@ export default {
this.$Router.push('/login');
}
},
computed:{
sessionData (){
return this.$store.state.imData.sort((a,b) => b.updateTimeStamp - a.updateTimeStamp);
}
},
methods:{
FormatDate,
openMsg(item){
Im.setCurSessionId(item.id);
if(item.type === 4){
if(JSON.parse(item.payload).type === 'system'){
this.$Router.push(`/messageSystem?sessionId=${item.id}`);
return false;
}
this.$store.commit('SET_SESSION_MSG_ID', item.id);
if(item.type === 3){
this.$Router.push(`/messageChat?sessionId=${item.id}`);
}else{
this.$Router.push(`/messageSystem`);
}
this.$Router.push(`/messageChat?sessionId=${item.id}`);
}
}
}
@ -112,8 +94,6 @@ export default {
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
word-break: break-all;
}
&--right{
text-align: right;

@ -0,0 +1,127 @@
<!--
* @Author: ch
* @Date: 2022-03-26 14:32:03
* @LastEditors: ch
* @LastEditTime: 2022-05-17 16:22:13
* @Description: file content
-->
<template>
<view class="main">
<view class="msg-item" v-for="item in msgData" :key="item.id">
<view class="msg-item--title">
<text>{{item.payload.title }} {{item.id}}</text>
<text class="msg-item--time">{{item.createTimeStamp}}</text>
</view>
<view class="msg-item--con">
<image class="msg-item--img" src="@/static/message/xt.png" mode="widthFix"/>
<view class="msg-item--desc">{{item.payload.content}}</view>
</view>
</view>
<u-loadmore status="loading" v-if="!msgData.length"/>
</view>
</template>
<script>
import {MsbWebSkt, createUUID} from '@/common/utils';
export default {
data(){
return {
}
},
computed:{
curSessionData(){
return this.$store.state.sessionData.find(i =>i.id == this.$store.state.sessionMsgId)
},
msgData (){
return this.curSessionData ? this.curSessionData.messageList : [];
}
},
onReachBottom(){
this.getHistoryMsg();
},
onShow(){
if(!this.$store.state.sessionMsgId){
this.$Router.back();
return false
}
uni.setNavigationBarTitle({
title : this.curSessionData.fromNickname
});
this.getHistoryMsg();
this.readMsg();
},
methods:{
/**
* 获取历史消息
*/
getHistoryMsg(){
this.loading = true;
const lastMsg = this.msgData[this.msgData.length - 1] || {};
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "2",
content: {
sessionId : this.$store.state.sessionMsgId,
topMessageId : lastMsg.id || null
}
})
})
},
/**
* 已读消息
*/
readMsg(){
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "6",
content: {
sessionId : this.$store.state.sessionMsgId
}
})
});
//
const count = this.$store.state.sessionMsgCount - this.curSessionData.unreadCount;
//
this.curSessionData.unreadCount = 0;
this.$store.commit('SET_SESSION_MSG_COUNT', count)
}
}
}
</script>
<style lang="scss" scoped>
.msg-item{
padding: 40rpx 0 0 40rpx;
&--title{
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 40rpx;
font-size: $font-size-lg;
color: $color-grey6;
}
&--time{
font-size: $font-size-sm;
color: $color-grey4;
}
&--con{
display: flex;
border-bottom: 1px solid $color-grey2;
padding: 40rpx 0;
}
&--img{
width: 140rpx;
height: 140rpx;
border-radius: 12rpx;
margin-right: 40rpx;
}
&--desc{
width: 455rpx;
font-size: $font-size-base;
line-height: 39rpx;
color: $color-grey5;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 15:09:06
* @LastEditors: ch
* @LastEditTime: 2022-06-23 17:45:29
* @LastEditTime: 2022-05-16 20:21:20
* @Description: file content
-->
<template>
@ -19,7 +19,7 @@
<script>
import UiButton from '@/components/UiButton.vue'
import UiCell from '@/components/UiCell.vue';
import {Im} from '@/common/utils';
import {MsbWebSkt} from '@/common/utils';
import {ApiGetLogout} from '@/common/api/index';
export default {
components: { UiCell, UiButton },
@ -28,7 +28,6 @@ export default {
return this.$store.state.userInfo
}
},
methods:{
logout(){
uni.showModal({
@ -38,13 +37,12 @@ export default {
confirmColor : '#3A83FB',
success:async ({confirm})=>{
if(confirm){
const {error} = await ApiGetLogout();
if(error){
uni.$u.toast(error.message);
return false;
}
await ApiGetLogout();
this.$store.commit('SET_SESSION_DATA',[])
this.$store.commit('SET_SESSION_MSG_COUNT',0)
this.$store.commit('SET_SESSION_MSG_ID','')
this.$store.commit('SET_TOKEN');
Im.close();
MsbWebSkt.close();
this.$Router.replace('/login');
}
}
@ -95,7 +93,7 @@ page {
font-size: $font-size-lg;
}
::v-deep{
/deep/{
.userInfo .uiCell--title{
font-size: $font-size-lg;
}

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

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

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

@ -301,22 +301,12 @@ export default {
* 结算选中的商品
*/
handleOrder() {
const ids = this.checkedIds;
//
const baseType = this.list.find(i => ids[0] === i.id).productType;
for(let id of ids){
const item = this.list.find(i => id === i.id);
if(item.productType != baseType){
uni.$u.toast('虚拟商品需要单独结算,不可和其他实物订单合并结算哦~');
return false;
}
}
const ids = this.checkedIds;
if (ids.length) {
this.$Router.push({
path : '/orderSubmit',
query : {
mode: 'cart',
productType : baseType,
ids:ids.join(',')
}
})
@ -583,7 +573,7 @@ export default {
}
::v-deep{
/deep/{
.cart-item--price{
text{
font-size: $font-size-lg;

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

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

@ -36,7 +36,7 @@
</view>
</template>
<script>
import {FormatDate} from '@/common/utils';
import {formatDate} from '@/common/utils';
export default {
props : {
data : {
@ -85,7 +85,7 @@ export default {
return currentTime.getDate() === activityTime.getDate();
},
startDate(){
return FormatDate(this.data.activityStartTime, 'm月d日hh:ii')
return formatDate(this.data.activityStartTime, 'm月d日hh:ii')
}
},
methods:{

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-24 11:30:55
* @LastEditors: ch
* @LastEditTime: 2022-05-26 15:43:55
* @LastEditTime: 2022-05-17 22:21:10
* @Description: file content
-->
<template>
@ -242,7 +242,6 @@ export default {
mode : 'buyNow',
skuId : this.curSku.skuId,
num : this.curBuyNum,
productType : this.goodsInfo.productType,
activityType : 1
}
const {productActivityVO} = this.goodsInfo;

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-23 17:27:21
* @LastEditors: ch
* @LastEditTime: 2022-07-04 16:26:33
* @LastEditTime: 2022-05-17 22:25:52
* @Description: file content
-->
<template>
@ -22,16 +22,14 @@
</view>
<view class="goods-info--title">{{goods.name}}</view>
</view>
<view class="box">
<view class="select">
<Service></Service>
<u-cell v-if="stock > 0" label="选择" :value="curSku.name || '请选择规格'" :border="false" isLink @click="onShowSkuPopup(1)"></u-cell>
<SkuPopup v-model="curSku" :visible.sync="showSkuPopup" :mode="skuMode"
:goodsInfo="goods" :skuInfo="skuInfoData" :activityStatus="activityStatus">
</SkuPopup>
</view>
<Comment v-if="commentCount" :commentList="commentList" :count="commentCount" :productId="goodsId"/>
<view class="box goods-desc">
<view class="goods-desc">
<mp-html :content="goods.detail"/>
</view>
<view class="footer--not-stock" v-if="stock === 0">~</view>
@ -49,23 +47,20 @@
</template>
<script>
import {FormatDate, HandleApiError} from '@/common/utils';
import {formatDate} from '@/common/utils';
import {ApiGetGoodsDetail, ApiGetGoodsSkus} from '@/common/api/goods';
import {ApiGetCommentList, ApiGetCommentCount} from '@/common/api/comment';
import SlideImage from './modules/SlideImage.vue';
import Service from './modules/Service.vue';
import SkuPopup from './modules/SkuPopup.vue';
import SeckillPrice from './modules/SeckillPrice.vue';
import SlideImage from './components/SlideImage.vue';
import Service from './components/Service.vue';
import SkuPopup from './components/SkuPopup.vue';
import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html';
import UiButton from '../../../components/UiButton.vue';
import Comment from './modules/Comment.vue';
import SeckillPrice from './components/SeckillPrice.vue';
export default {
components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice, Comment},
components: { SlideImage, mpHtml, Service, SkuPopup, UiButton, SeckillPrice},
data(){
return {
// 1
stock : 1,
goodsId : this.$Route.query.id,
goods : {
pictureList : []
},
@ -78,10 +73,7 @@ export default {
sku : '',
num : 1
},
productActivityVO : {},
commentList : [],
commentCount : 0
productActivityVO : {}
}
},
computed:{
@ -104,11 +96,8 @@ export default {
async getGoodsDetail(){
const {query} = this.$Route;
const {error, result} = await ApiGetGoodsDetail({id : query.id});
if(HandleApiError(error, 'getGoodsDetail')){
return false;
}
if(!result.isEnable){
this.$Router.replace('/enable')
if(error){
uni.$u.toast(error.message);
return false;
}
this.goods = {...result,
@ -118,9 +107,9 @@ export default {
if(seckillVO.isActivity){
seckillVO = {
...seckillVO,
activityStartTime :FormatDate(seckillVO.activityStartTime,'yyyy/MM/dd hh:ii:ss'),
activityEndTime : FormatDate(seckillVO.activityEndTime,'yyyy/MM/dd hh:ii:ss'),
currentTime : FormatDate(seckillVO.currentTime,'yyyy/MM/dd hh:ii:ss'),
activityStartTime :formatDate(seckillVO.activityStartTime,'yyyy/MM/dd hh:ii:ss'),
activityEndTime : formatDate(seckillVO.activityEndTime,'yyyy/MM/dd hh:ii:ss'),
currentTime : formatDate(seckillVO.currentTime,'yyyy/MM/dd hh:ii:ss'),
}
}
//
@ -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;
});
const {query} = this.$Route;
const {error, result} = await ApiGetGoodsSkus({productId : query.id});
if(error) {
uni.$u.toast(error.message);
return false;
}
},
async getCommentCount (){
const {error, result} = await ApiGetCommentCount({
productId : this.goods.id
//
this.stock = 0;
this.skuInfoData = result.map(i => {
this.stock += i.stock;
// i.attributeSymbolList = i.attributeSymbolList.split(',')
return i;
});
if(!HandleApiError(error, 'getCommentCount')){
this.commentCount = result.allCommentCount;
}
},
async getComment(){
const {error, result} = await ApiGetCommentList({
pageIndex : 1,
length : 2,
productId : this.goods.id,
isContent : true,
sortType : 1
});
if(!HandleApiError(error, 'getComment')){
this.commentList = result.records;
}
},
/**
* 显示/隐藏SKU弹窗
@ -176,13 +145,13 @@ export default {
this.showSkuPopup = true
},
service(){
this.$Router.push({
path : '/messageChat',
query: {
goodsId : this.goods.id
}
})
// uni.$u.toast('~')
// this.$Router.push({
// path : '/messageChat',
// query: {
// goodsId : this.goods.id
// }
// })
uni.$u.toast('客服休息中,遇到喜欢的宝贝就下单吧~')
}
}
@ -200,7 +169,10 @@ page {
width: 50rpx;
height: 50rpx;
left: 40rpx;
/* #ifdef H5 */
top: 40rpx;
/* #endif */
/* #ifndef H5 */
top: 128rpx;
/* #endif */
@ -237,12 +209,15 @@ page {
}
.box{
.select{
margin: 20rpx 30rpx;
background: $color-grey0;
border-radius: 16rpx;
}
.goods-desc{
margin: 20rpx 30rpx;
background: $color-grey0;
border-radius: 16rpx;
padding: 20rpx;
}
.footer{

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

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-23 10:29:07
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:02
* @LastEditTime: 2022-05-06 11:20:23
* @Description: file content
-->
<template>
@ -165,19 +165,16 @@ export default {
margin-top: 0;
}
}
::v-deep {
.price{
text{
color: $color-yellow4;
font-size: $font-size-lg;
line-height: $font-size-lg;
font-weight: bold;
}
.ui-money--prefix{
font-size: $font-size-sm;
line-height: $font-size-sm;
}
/deep/ .price{
text{
color: $color-yellow4;
font-size: $font-size-lg;
line-height: $font-size-lg;
font-weight: bold;
}
.ui-money--prefix{
font-size: $font-size-sm;
line-height: $font-size-sm;
}
}
</style>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-23 10:07:48
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:16
* @LastEditTime: 2022-04-21 16:45:14
* @Description: file content
-->
<template>
@ -204,8 +204,8 @@ export default {
}
.seckill--item-pirce ::v-deep{
/deep/ {
.seckill--item-pirce{
text{
color: $color-yellow4;
font-size: $font-size-lg;
@ -215,6 +215,6 @@ export default {
font-size: $font-size-base;
}
}
}
</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-05-06 15:29:41
* @Description: file content
-->
<template>
@ -13,7 +13,7 @@
<text class="search--input">请输入您想搜索的商品名称</text>
</view>
<view class="msg" @click="$Router.push('/messageGroup')">
<u-badge class="msg--badge" max="99" :value="$store.state.imMsgCount"></u-badge>
<u-badge class="msg--badge" max="99" :value="$store.state.sessionMsgCount"></u-badge>
<image class="msg--icon" src="@/static/index/msg.png"></image>
</view>
</view>
@ -24,9 +24,9 @@
<view class="category">
<view class="category--item" v-for="item in categoryList" :key="item.id"
@click="AdJump(item)">
@click="$Router.push(`/goodsList?categoryId=${item.id}`)">
<view class="category--image-box">
<image class="category--image" :src="item.pictureUrl"></image>
<image class="category--image" :src="item.picture"></image>
</view>
<text class="category--title">{{item.name}}</text>
</view>
@ -44,22 +44,33 @@
</template>
<script>
import BsChoiceGoods from '@/components/BsChoiceGoods';
import Seckill from './modules/Seckill';
import Pick from './modules/Pick';
import Banner from './modules/Banner';
import Seckill from './components/Seckill';
import Pick from './components/Pick';
import Banner from './components/Banner';
import {ApiGetBannerData} from '@/common/api/index.js';
import {ApiGetHomeSeckill} from '@/common/api/seckill.js';
import {ApiGetCategoryNav, ApiGetRecommendedGoodsList} from '@/common/api/goods.js';
import {ApiGetAdList} from '@/common/api/ad.js';
import {AD_LOCATION} from '@/common/dicts/ad.js';
import {AdJump} from '@/common/utils';
export default {
components : {BsChoiceGoods, Pick, Banner, Seckill},
data(){
return {
scrollTop : 0,
bannerList: [],
categoryList : [],
bannerList: [
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/banner4.jpg',
id : 13
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/1.png',
id : 30
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/2banner.png',
id : 15
},
{ url : 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/uc/account-avatar/3banner.png',
id : 40
}
],
categoryList : [
],
recommendedGoodsList : [],
seckillData : {activityTimeVO:{}}
@ -69,7 +80,6 @@ export default {
this.getCategoryList();
this.getRecommendedGoodsList();
this.getSeckillList();
this.getBannerData();
},
onReachBottom(){
this.$refs.goodsGroup.next();
@ -90,11 +100,10 @@ export default {
},
methods : {
async getCategoryList(){
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_HARDCOVER
});
this.categoryList = result;
const {error, result} = await ApiGetCategoryNav();
if(result){
this.categoryList = result;
}
},
async getRecommendedGoodsList(){
@ -104,19 +113,12 @@ export default {
}
},
async getBannerData(){
const {error, result} = await ApiGetAdList({
location : AD_LOCATION.HOME_BANNER
});
this.bannerList = result || [];
},
async getSeckillList(){
const {error, result} = await ApiGetHomeSeckill();
if(result){
this.seckillData = result;
this.seckillData = result
}
},
AdJump
}
}
}
</script>

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-22 15:36:46
* @LastEditors: ch
* @LastEditTime: 2022-06-13 10:20:21
* @LastEditTime: 2022-05-17 20:03:12
* @Description: file content
-->
<template>
@ -31,8 +31,7 @@
</view>
</template>
<script>
import { IsPhone,MsbWebSkt, MsbWebSktInit, CreateUUID } from '@/common/utils';
import { Im, ImInit} from '@/common/utils';
import { IsPhone,MsbWebSkt, MsbWebSktInit, createUUID } from '@/common/utils';
import { ApiGetCode, ApiPostLogin } from '@/common/api/index';
import { ApiPostThirdInfo } from '@/common/api/wx';
import UiButton from '../components/UiButton.vue';
@ -114,14 +113,26 @@ export default {
});
}
MsbWebSktInit().then(()=>{
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "1",
content: { sysId : "1"}
})
});
// IM
ImInit().then(() => {
//
Im.getSessionList();
});
setInterval(()=>{
MsbWebSkt.send({
data : JSON.stringify({
traceId : createUUID(),
traceType : "0",
content: { text : "ping"}
})
})
}, 5000);
})
this.goBack();
},
/**
@ -218,7 +229,7 @@ export default {
}
}
}
::v-deep{
/deep/{
.input-placeholder{
color: $color-grey3;
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-15 16:36:02
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:18
* @LastEditTime: 2022-04-22 21:10:56
* @Description: file content
-->
<template>
@ -81,7 +81,7 @@ export default {
}
}
::v-deep{
/deep/{
.u-cell__body__content{
padding: 10rpx 0;
}

@ -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-17 18:00:17
* @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(){
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
uni.$u.toast('客服休息中')
// this.$Router.push({
// path : '/messageChat',
// query : {
// orderId : this.orderInfo.orderId
// }
// })
}
}
}

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-04-15 16:04:28
* @LastEditors: ch
* @LastEditTime: 2022-05-24 09:57:19
* @LastEditTime: 2022-04-22 15:30:50
* @Description: file content
-->
<template>
@ -103,7 +103,7 @@ export default {
color: $color-yellow4;
font-size: $font-size-lg;
}
::v-deep {
/deep/ {
.ui-money--price{
font-size: 36rpx;
color: $color-yellow4;

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

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-03-31 14:26:09
* @LastEditors: ch
* @LastEditTime: 2022-06-22 11:22:41
* @LastEditTime: 2022-05-13 15:04:20
* @Description: file content
-->
<template>
@ -14,7 +14,7 @@
<template slot="operation">
<view class="goods-info-operation" v-if="item.afterSaleApplyFlag || [2,3,4].includes(item.detailStatus)">
<UiButton size="min" type="primaryLine" v-if="item.afterSaleApplyFlag"
@click="handleSaleAfter(item)">申请售后</UiButton>
@click="$Router.push(`/saleAfterSelect?id=${item.orderProductId}`)">申请售后</UiButton>
<template v-else>
<UiButton size="min" type="line"
@click="$Router.push(`/saleAfterDetail?orderProductId=${item.orderProductId}`)">
@ -29,8 +29,7 @@
</template>
</UiGoodsInfo>
</UiWhiteBox>
<LogisitcsInfo v-if="orderInfo.orderType !== ORDER.TYPE.VIRTUAL"
:logisitcsInfo="orderInfo.logistics" :orderId="orderInfo.orderId"/>
<LogisitcsInfo :logisitcsInfo="orderInfo.logistics" :orderId="orderInfo.orderId"/>
<OrderInfo :orderInfo="orderInfo" />
<Operation :orderInfo="orderInfo" v-if="orderInfo.orderStatus !== 3"></Operation>
</view>
@ -40,16 +39,14 @@ import UiGoodsInfo from '@/components/UiGoodsInfo.vue';
import UiWhiteBox from '@/components/UiWhiteBox.vue';
import UiButton from '@/components/UiButton.vue';
import {ApiGetOrderDetail, ApiPutCancelOrder} from '@/common/api/order';
import StatusTips from './modules/StatusTips.vue';
import OrderInfo from './modules/OrderInfo.vue';
import LogisitcsInfo from './modules/LogisitcsInfo.vue';
import Operation from './modules/Operation.vue';
import ORDER from '@/common/dicts/order'
import StatusTips from './components/StatusTips.vue';
import OrderInfo from './components/OrderInfo.vue';
import LogisitcsInfo from './components/LogisitcsInfo.vue';
import Operation from './components/Operation.vue';
export default {
components: { UiGoodsInfo, UiWhiteBox, UiButton, StatusTips, OrderInfo, LogisitcsInfo, Operation },
data(){
return {
ORDER,
orderInfo : {
products:[],
logistics:{}
@ -77,14 +74,6 @@ export default {
timerCloseOrder(){
this.orderInfo = {...this.orderInfo, orderStatus : 2, cancelReason:'超时未支付'};
this.getOrderInfo();
},
handleSaleAfter(item){
if(this.orderInfo.orderType === ORDER.TYPE.VIRTUAL){
uni.$u.toast('虚拟商品的订单不满足退款要求,不支持申请售后,如有问题请联系客服。');
}else{
this.$Router.push(`/saleAfterSelect?id=${item.orderProductId}`)
}
}
}

@ -2,13 +2,13 @@
* @Author: ch
* @Date: 2022-03-22 10:58:24
* @LastEditors: ch
* @LastEditTime: 2022-07-13 18:21:13
* @LastEditTime: 2022-05-07 19:08:18
* @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')
}
}
})
@ -269,7 +240,7 @@ page {
}
}
::v-deep{
/deep/{
.orders--footer{
.ui-btn{
margin: 0 0 0 20rpx;

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

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

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

@ -191,7 +191,7 @@ export default {
padding: 0 30rpx;
}
.address{
::v-deep.u-cell__body__content{
/deep/.u-cell__body__content{
padding: 10rpx 0;
}

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

Loading…
Cancel
Save