Compare commits
No commits in common. "gaohao" and "master" have entirely different histories.
40
api/http.js
40
api/http.js
|
|
@ -10,13 +10,12 @@
|
||||||
// 导入全局属性
|
// 导入全局属性
|
||||||
import appConfig from '@/config/appConfig.js'
|
import appConfig from '@/config/appConfig.js'
|
||||||
import storageManage from '@/commons/utils/storageManage.js'
|
import storageManage from '@/commons/utils/storageManage.js'
|
||||||
|
import {
|
||||||
// let baseUrl = '' //测试
|
sm4DecryptByResData
|
||||||
// let baseUrl = 'https://cashier-client.sxczgkj.cn/cashier-client' //测试环境
|
} from '@/commons/utils/encryptUtil.js'
|
||||||
// let baseUrl = 'https://pre-cashierclient.sxczgkj.cn/cashier-client' //预发布环境
|
import infoBox from "@/commons/utils/infoBox.js"
|
||||||
// let baseUrl = 'https://cashierclient.sxczgkj.cn/cashier-client' //线上环境
|
// let baseUrl = ''
|
||||||
let baseUrl = appConfig.ENV_ENUM.VITE_API_URL
|
let baseUrl = 'https://cashier-client.sxczgkj.cn/cashier-client'
|
||||||
|
|
||||||
// 多少 ms 以内, 不提示loading
|
// 多少 ms 以内, 不提示loading
|
||||||
const loadingShowTime = 200
|
const loadingShowTime = 200
|
||||||
|
|
||||||
|
|
@ -46,7 +45,7 @@ function commonsProcess(showLoading, httpReqCallback) {
|
||||||
let reqFinishFunc = () => {
|
let reqFinishFunc = () => {
|
||||||
|
|
||||||
if (reqState == 'ingLoading') { // 关闭loading弹层
|
if (reqState == 'ingLoading') { // 关闭loading弹层
|
||||||
uni.hideLoading()
|
infoBox.hideLoading()
|
||||||
}
|
}
|
||||||
reqState = 'finish' // 请求完毕
|
reqState = 'finish' // 请求完毕
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +56,7 @@ function commonsProcess(showLoading, httpReqCallback) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (reqState == 'ing') {
|
if (reqState == 'ing') {
|
||||||
reqState = 'ingLoading'
|
reqState = 'ingLoading'
|
||||||
uni.showLoading({ title: '请稍后', mask: true })
|
infoBox.showLoading()
|
||||||
}
|
}
|
||||||
}, loadingShowTime)
|
}, loadingShowTime)
|
||||||
}
|
}
|
||||||
|
|
@ -88,10 +87,7 @@ function commonsProcess(showLoading, httpReqCallback) {
|
||||||
// http响应码不正确
|
// http响应码不正确
|
||||||
if (statusCode != 200 && statusCode != 204 && statusCode != 201) {
|
if (statusCode != 200 && statusCode != 204 && statusCode != 201) {
|
||||||
isShowErrorToast = true
|
isShowErrorToast = true
|
||||||
uni.showToast({
|
infoBox.showErrorToast(data.message || '服务器异常')
|
||||||
title: data.message || '服务器异常',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return Promise.reject(bodyData) // 跳转到catch函数
|
return Promise.reject(bodyData) // 跳转到catch函数
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,25 +97,19 @@ function commonsProcess(showLoading, httpReqCallback) {
|
||||||
|
|
||||||
}).catch(res => {
|
}).catch(res => {
|
||||||
if(res.status==401){
|
if(res.status==401){
|
||||||
uni.showToast({
|
infoBox.showToast(`登录失效`)
|
||||||
title: '登录失效',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if(res.status==500){
|
if(res.status==500){
|
||||||
uni.showToast({
|
infoBox.showToast(`网络异常`)
|
||||||
title: '网络异常',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
// if(res&&res.msg){
|
||||||
|
// infoBox.showErrorToast(res.msg)
|
||||||
|
// }
|
||||||
reqFinishFunc(); // 请求完毕的动作
|
reqFinishFunc(); // 请求完毕的动作
|
||||||
|
|
||||||
// 如果没有提示错误, 那么此处提示 异常。
|
// 如果没有提示错误, 那么此处提示 异常。
|
||||||
if (!isShowErrorToast) {
|
if (!isShowErrorToast) {
|
||||||
uni.showToast({
|
infoBox.showErrorToast(`请求网络异常`)
|
||||||
title: '请求网络异常',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(res)
|
return Promise.reject(res)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* 数字, 计算相关函数
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2022/11/22 10:38
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保留小数n位,不进行四舍五入
|
||||||
|
* num你传递过来的数字,
|
||||||
|
* decimal你保留的几位,默认保留小数后两位
|
||||||
|
*/
|
||||||
|
const formatDecimal = function(num, decimal = 2) {
|
||||||
|
num = num.toString()
|
||||||
|
const index = num.indexOf('.')
|
||||||
|
if (index !== -1) {
|
||||||
|
num = num.substring(0, decimal + index + 1)
|
||||||
|
} else {
|
||||||
|
num = num.substring(0)
|
||||||
|
}
|
||||||
|
//截取后保留两位小数
|
||||||
|
return parseFloat(num).toFixed(decimal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
// 分转元
|
||||||
|
// amount - 金额 parseFloat - 是否转换为数字格式, 默认String
|
||||||
|
cert2Dollar(amount, needParseFloat = false) {
|
||||||
|
if (needParseFloat) { // parseFlot
|
||||||
|
return formatDecimal(amount / 100)
|
||||||
|
}
|
||||||
|
return formatDecimal(amount / 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* 数据 工具类
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2022/11/30 14:18
|
||||||
|
*/
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
|
||||||
|
// 递归遍历树状结构数据 matchFunc 匹配结果, true表示匹配成功, 否则继续匹配。
|
||||||
|
// pnode 可不传入
|
||||||
|
// 返回结构: [当前数据, 上级数据 ]
|
||||||
|
recursionTreeData: (treeData, matchFunc, childrenName = 'children', pnode = null ) => {
|
||||||
|
|
||||||
|
for (let i = 0; i < treeData.length; i++) {
|
||||||
|
|
||||||
|
const item = treeData[i]
|
||||||
|
|
||||||
|
// 匹配成功
|
||||||
|
if(matchFunc(item)){
|
||||||
|
return [item, pnode]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item[childrenName] && item[childrenName].length > 0) {
|
||||||
|
let res = model.recursionTreeData(item[childrenName], matchFunc, childrenName, item)
|
||||||
|
if(res){
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
* 加解密工具包
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2021/5/16 17:35
|
||||||
|
*/
|
||||||
|
import { SM4 } from 'gm-crypto'
|
||||||
|
import appConfig from '@/config/appConfig.js'
|
||||||
|
|
||||||
|
let HEX_KEY = null
|
||||||
|
|
||||||
|
// 字符串转16进制
|
||||||
|
function str2hex(str) {
|
||||||
|
var val = ''
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
if (val == '')
|
||||||
|
val = str.charCodeAt(i).toString(16)
|
||||||
|
else
|
||||||
|
val += str.charCodeAt(i).toString(16)
|
||||||
|
}
|
||||||
|
val += ''
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取hex秘钥
|
||||||
|
function getHexKey(){
|
||||||
|
|
||||||
|
if(!HEX_KEY){
|
||||||
|
|
||||||
|
HEX_KEY = str2hex(appConfig.encryptKey)
|
||||||
|
|
||||||
|
}
|
||||||
|
return HEX_KEY
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 解密 (http响应数据, 做通用处理)
|
||||||
|
export function sm4DecryptByResData(data){
|
||||||
|
|
||||||
|
if(!data){
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = SM4.decrypt(data, getHexKey(), {
|
||||||
|
inputEncoding: 'base64',
|
||||||
|
outputEncoding: 'utf8'
|
||||||
|
})
|
||||||
|
|
||||||
|
if(!res){
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(res)['originData']
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密 (http响应数据, 做通用处理)
|
||||||
|
export function sm4EncryptByReqData(data){
|
||||||
|
|
||||||
|
if(!data){
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密处理
|
||||||
|
let encryptData = SM4.encrypt(JSON.stringify(data), getHexKey(), {
|
||||||
|
inputEncoding: 'utf8',
|
||||||
|
outputEncoding: 'base64'
|
||||||
|
})
|
||||||
|
|
||||||
|
return {encryptData : encryptData}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* form 验证 工具类
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeepay.vip
|
||||||
|
* @date 2022/11/25 10:58
|
||||||
|
*/
|
||||||
|
|
||||||
|
import infoBox from '@/commons/utils/infoBox.js'
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
|
||||||
|
|
||||||
|
// 正则表达式
|
||||||
|
regexp: {
|
||||||
|
|
||||||
|
// 手机号验证规则
|
||||||
|
mobile: /^1\d{10}$/,
|
||||||
|
|
||||||
|
// 登录用户名: 字母开头 6 -18位。
|
||||||
|
loginUsername: /^[a-zA-Z][a-zA-Z0-9]{5,17}$/,
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// 验证规则:
|
||||||
|
rules: {
|
||||||
|
|
||||||
|
// showText 为空, 说明是 input的placeHoloder 直接飘红,
|
||||||
|
// showText 有值: 在文本框下方提示。
|
||||||
|
// 只有input 才有这种特殊判断。
|
||||||
|
requiredInput: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage: showText ? ('请输入' + showText) : ' ' }
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredSelect: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage: '请选择' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredUpload: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage: '请上传' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
// 正则验证 , 请注意: 该规则需要在required后面, 此处不可包含required
|
||||||
|
patternRule: (showText, p) => {
|
||||||
|
return {pattern: p, errorMessage: '请输入正确的' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredInputShowToast: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请输入' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredSelectShowToast: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请选择' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredUploadShowToast: (showText, type = 'string') => {
|
||||||
|
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请上传' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
patternRuleShowToast: (showText, p) => {
|
||||||
|
return {pattern: p, errorMessage:' ', toastErrorMessage: '请输入正确的' + showText }
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// 支持 提示信息
|
||||||
|
// 类型如下:
|
||||||
|
// {
|
||||||
|
// required: true,
|
||||||
|
// toastErrorMessage: "请输入去去去去群",
|
||||||
|
// errorMessage: ' ', // 不会显示在下部, 需要空格占位
|
||||||
|
// }
|
||||||
|
validate: (form) => {
|
||||||
|
|
||||||
|
return form.validate().catch(e => {
|
||||||
|
|
||||||
|
if(!e || e.length <= 0){
|
||||||
|
return Promise.reject()
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 0; i < e.length; i++){
|
||||||
|
let k = e[i].key
|
||||||
|
let rules = form.rules[k].rules
|
||||||
|
for(let j = 0; j < rules.length; j++){
|
||||||
|
if(rules[j].toastErrorMessage && rules[j].required){
|
||||||
|
infoBox.showToast(rules[j].toastErrorMessage) // 仅提示一次即可
|
||||||
|
return Promise.reject(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* 格式化价格函数,将价格限定在指定的最小值和最大值范围内,并保留两位小数。
|
||||||
|
*
|
||||||
|
* @param {number} price - 需要格式化的价格。
|
||||||
|
* @param {number} min - 价格的最小值。
|
||||||
|
* @param {number} max - 价格的最大值,默认为100000000。
|
||||||
|
* @param {Boolean} returnIsArea - 是否返回值符合范围区间,默认为false。
|
||||||
|
* @returns {number} - 返回格式化后的价格,如果超出范围则返回最小值或最大值。
|
||||||
|
*/
|
||||||
|
export const formatPrice = (price,min=-Infinity, max = 100000000,returnIsArea=false ) => {
|
||||||
|
if(price === undefined || price === null||price===''){
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// 将价格转换为浮点数并保留两位小数
|
||||||
|
const newval = parseFloat((Math.floor(price * 100) / 100).toFixed(2))
|
||||||
|
// 如果价格大于最大值,返回最大值
|
||||||
|
if (newval > max) {
|
||||||
|
return returnIsArea?{value:max,error:true}:max
|
||||||
|
}
|
||||||
|
// 如果价格小于最小值,返回最小值
|
||||||
|
if (newval < min) {
|
||||||
|
return returnIsArea?{value:min,error:true}:min
|
||||||
|
}
|
||||||
|
// 如果价格小于最小值,返回最小值
|
||||||
|
if (newval < min) {
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
// 返回格式化后的价格
|
||||||
|
return newval
|
||||||
|
}
|
||||||
|
export function returnReverseVal(val, isReturnString = true) {
|
||||||
|
const isBol = typeof val === "boolean";
|
||||||
|
const isString = typeof val === "string";
|
||||||
|
let reverseNewval = "";
|
||||||
|
if (isBol) {
|
||||||
|
reverseNewval = !val;
|
||||||
|
}
|
||||||
|
if (isString) {
|
||||||
|
reverseNewval = val === "true" ? "false" : "true";
|
||||||
|
}
|
||||||
|
return reverseNewval;
|
||||||
|
}
|
||||||
|
export function returnBoolean(val) {
|
||||||
|
const isBol = typeof val === "boolean";
|
||||||
|
const isString = typeof val === "string";
|
||||||
|
let newval = "";
|
||||||
|
if (isBol) {
|
||||||
|
newval = val;
|
||||||
|
}
|
||||||
|
if (isString) {
|
||||||
|
newval = val === "true" ? true : false;
|
||||||
|
}
|
||||||
|
return newval;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
function getDayArea(date = new Date(), type) {
|
||||||
|
const now = date
|
||||||
|
if (type === 'start') {
|
||||||
|
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||||
|
return startOfDay
|
||||||
|
}
|
||||||
|
if (type === 'end') {
|
||||||
|
const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
|
||||||
|
return endOfDay;
|
||||||
|
}
|
||||||
|
return `${startOfDay}-${endOfDay}`
|
||||||
|
}
|
||||||
|
function getMonthArea(date = new Date(), type) {
|
||||||
|
let now = date
|
||||||
|
let currentMonthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||||
|
let currentMonthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0 , 23, 59, 59, 999);
|
||||||
|
if (type === 'start') {
|
||||||
|
return currentMonthStart
|
||||||
|
}
|
||||||
|
if (type === 'end') {
|
||||||
|
return currentMonthEnd;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
start: currentMonthStart,
|
||||||
|
end: currentMonthEnd
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getDayArea, getMonthArea
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* 获取url链接参数
|
||||||
|
* @param {Object} url
|
||||||
|
* @param {Object} name
|
||||||
|
*/
|
||||||
|
export function getQueryString(url, name) {
|
||||||
|
var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
|
||||||
|
var r = url.substr(1).match(reg)
|
||||||
|
if (r != null) {
|
||||||
|
return r[2]
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* 提示信息公共文件
|
||||||
|
*
|
||||||
|
* @author terrfly
|
||||||
|
* @site https://www.jeequan.com
|
||||||
|
* @date 2022/11/14 15:29
|
||||||
|
*/
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
|
||||||
|
// uni.showToast的封装
|
||||||
|
// 参数: 标题、 显示时长(单位: 秒), 扩展参数
|
||||||
|
// 返回: promise对象, 当提示消失后调用 resolve()
|
||||||
|
showToast: (title, duration = 1.5, extObject) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showToast(Object.assign({ title: title, icon: 'none', mask: true, duration: (duration * 1000) }, extObject))
|
||||||
|
setTimeout(resolve, (duration * 1000));
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// success类型的提示
|
||||||
|
showSuccessToast: (title, duration) => {
|
||||||
|
return model.showToast(title, duration, {icon: 'success'})
|
||||||
|
},
|
||||||
|
|
||||||
|
// error类型的提示
|
||||||
|
showErrorToast: (title, duration) => {
|
||||||
|
return model.showToast(title, duration, {icon: 'error'})
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoading: (title = '请稍后' ) => {
|
||||||
|
return uni.showLoading({ title: title, mask: true })
|
||||||
|
},
|
||||||
|
|
||||||
|
hideLoading: () => {
|
||||||
|
return uni.hideLoading()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 返回 Promise 点击确定和取消
|
||||||
|
// APP安卓原生提示(比较丑), APP 不推荐使用该函数 。
|
||||||
|
showModal: (title, confirmText = '确定', cancalText = '取消', extObject) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showModal( Object.assign({
|
||||||
|
title: title,
|
||||||
|
confirmText: confirmText,
|
||||||
|
showCancel: cancalText ? true : false,
|
||||||
|
cancelText: cancalText,
|
||||||
|
success: function(r) {
|
||||||
|
if (r.confirm) {
|
||||||
|
resolve()
|
||||||
|
}else if (r.cancel) {
|
||||||
|
reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, extObject ));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default model
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
import { $getBaiduToken } from '@/http/apiManager.js';
|
||||||
|
const audioTeam = [];
|
||||||
|
let audioStartSwitch = false;
|
||||||
|
const getAudioUrl = 'https://tsn.baidu.com/text2audio';
|
||||||
|
|
||||||
|
export default function openVoice(objs) { // 传入需转为语音的文本内容
|
||||||
|
let lineUp = false;
|
||||||
|
let returnAudio = false;
|
||||||
|
if (typeof(objs) !== 'string') {
|
||||||
|
if (objs && objs.lineUp === true) {
|
||||||
|
lineUp = true;
|
||||||
|
}
|
||||||
|
if (objs && objs.returnAudio === true) {
|
||||||
|
returnAudio = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(returnAudio) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
openVoiceFc(objs, returnAudio).then(res=>{
|
||||||
|
resolve(res);
|
||||||
|
}).catch(err=>{
|
||||||
|
reject(err)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!audioStartSwitch || lineUp) {
|
||||||
|
audioStartSwitch = true;
|
||||||
|
openVoiceFc(objs);
|
||||||
|
} else {
|
||||||
|
audioTeam.push(objs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openVoiceFc(objs, returnAudio) {
|
||||||
|
if(returnAudio) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
$getBaiduToken().then(({bizData}) => {
|
||||||
|
if (bizData) {
|
||||||
|
resolve(tts(objs, bizData, returnAudio));
|
||||||
|
} else {
|
||||||
|
reject('获取语音tok接口为空');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
$getBaiduToken().then(({bizData}) => {
|
||||||
|
if (bizData) {
|
||||||
|
tts(objs, bizData);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tts(objs, tok, returnAudio) {
|
||||||
|
if(typeof(objs)=='string')
|
||||||
|
objs = {voiceSet: {tex: objs}};
|
||||||
|
const data = {
|
||||||
|
tok,
|
||||||
|
cuid: tok,
|
||||||
|
ctp: 1,
|
||||||
|
lan: 'zh',
|
||||||
|
...objs.voiceSet
|
||||||
|
}
|
||||||
|
if(returnAudio)
|
||||||
|
return btts( data, objs.audioSet, objs.audioCallback, objs.lineUp, returnAudio);
|
||||||
|
btts( data, objs.audioSet, objs.audioCallback, objs.lineUp, returnAudio);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAudioSet(options, audio) {
|
||||||
|
if (options) {
|
||||||
|
audio.volume = options.volume || 1;
|
||||||
|
audio.startTime = options.startTime || 0;
|
||||||
|
audio.loop = options.loop || false;
|
||||||
|
audio.obeyMuteSwitch = options.obeyMuteSwitch && typeof(options.obeyMuteSwitch) == 'boolean' ? options.obeyMuteSwitch :
|
||||||
|
true; //支持微信小程序、百度小程序、头条小程序
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function btts(param, options, audioCallback, lineUp, returnAudio) {
|
||||||
|
let audio = uni.createInnerAudioContext();
|
||||||
|
setAudioSet(options, audio);
|
||||||
|
// 序列化参数列表
|
||||||
|
let fd = [];
|
||||||
|
for (let k in param) {
|
||||||
|
fd.push(k + '=' + encodeURIComponent(encodeURIComponent(param[k])));
|
||||||
|
}
|
||||||
|
audio.src = `${getAudioUrl}?${fd.join('&')}`;
|
||||||
|
|
||||||
|
if(returnAudio) {
|
||||||
|
audio.onEnded(() => {
|
||||||
|
audio.destroy(); //销毁音频实例
|
||||||
|
audio = null;
|
||||||
|
})
|
||||||
|
audio.onError((e)=>{
|
||||||
|
if (audioCallback && audioCallback.onError && typeof(audioCallback.onError) == 'function') audioCallback.onError(e);
|
||||||
|
audio.destroy(); //销毁音频实例
|
||||||
|
audio = null;
|
||||||
|
})
|
||||||
|
return audio;
|
||||||
|
}
|
||||||
|
audio.onPlay(() => {
|
||||||
|
if (audioCallback && audioCallback.onPlay && typeof(audioCallback.onPlay) == 'function') audioCallback.onPlay();
|
||||||
|
})
|
||||||
|
audio.onPause(()=>{
|
||||||
|
if (audioCallback && audioCallback.onPause && typeof(audioCallback.onPause) == 'function') audioCallback.onPause();
|
||||||
|
})
|
||||||
|
audio.onWaiting(()=>{
|
||||||
|
if (audioCallback && audioCallback.onWaiting && typeof(audioCallback.onWaiting) == 'function') audioCallback.onWaiting();
|
||||||
|
})
|
||||||
|
audio.onStop(()=>{
|
||||||
|
if (audioCallback && audioCallback.onStop && typeof(audioCallback.onStop) == 'function') audioCallback.onStop();
|
||||||
|
})
|
||||||
|
audio.onTimeUpdate(()=>{
|
||||||
|
if (audioCallback && audioCallback.onTimeUpdate && typeof(audioCallback.onTimeUpdate) == 'function') audioCallback.onTimeUpdate();
|
||||||
|
})
|
||||||
|
audio.onSeeking(()=>{
|
||||||
|
if (audioCallback && audioCallback.onSeeking && typeof(audioCallback.onSeeking) == 'function') audioCallback.onSeeking();
|
||||||
|
})
|
||||||
|
audio.onSeeked(()=>{
|
||||||
|
if (audioCallback && audioCallback.onSeeked && typeof(audioCallback.onSeeked) == 'function') audioCallback.onSeeked();
|
||||||
|
})
|
||||||
|
audio.onEnded(() => {
|
||||||
|
audio.destroy(); //销毁音频实例
|
||||||
|
audio = null;
|
||||||
|
if (audioCallback && audioCallback.onEnded && typeof(audioCallback.onEnded) == 'function') audioCallback.onEnded();
|
||||||
|
if (lineUp !== false) {
|
||||||
|
if (audioTeam.length > 0) {
|
||||||
|
openVoiceFc(audioTeam[0]);
|
||||||
|
audioTeam.splice(0, 1);
|
||||||
|
} else {
|
||||||
|
audioStartSwitch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
audio.onError((e)=>{
|
||||||
|
if (audioCallback && audioCallback.onError && typeof(audioCallback.onError) == 'function') audioCallback.onError(e);
|
||||||
|
audio.destroy(); //销毁音频实例
|
||||||
|
audio = null;
|
||||||
|
})
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import storageManage from '@/commons/utils/storageManage.js'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import baiduyy from './QS-baiduyy.js'; // 百度语音合成
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
import wxTextToSpeach from './wxTextToSpeach.js'; // 微信小程序插件语音合成
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
// 监听推送通知
|
||||||
|
addPushMsgEventListener: function(){
|
||||||
|
|
||||||
|
console.log("监听推送")
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
// unipush1.0监听消息
|
||||||
|
if(plus && plus.push) {
|
||||||
|
plus.push.addEventListener('receive', model.handlePush)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// unipush2.0监听消息
|
||||||
|
model.uniPushListener2()
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// uniPush2.0 接收推送消息
|
||||||
|
uniPushListener2: function() {
|
||||||
|
uni.onPushMessage((res) => {
|
||||||
|
console.log("uniPush2.0 收到推送消息:", res.data) //监听推送消息
|
||||||
|
model.handlePush(res.data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 语音播报
|
||||||
|
handlePush: function(message) {
|
||||||
|
|
||||||
|
// 没有token信息
|
||||||
|
if(!storageManage.token()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 信息不存在
|
||||||
|
if(!message || !message.content) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = JSON.parse(message.content)
|
||||||
|
console.log("消息内容:", content)
|
||||||
|
|
||||||
|
// 支付成功
|
||||||
|
if (content && content.type == 'paySuccess') {
|
||||||
|
// 在过期时间之内, 则调起语音播报。
|
||||||
|
if( dayjs(content.expiredTime).isAfter(dayjs()) ){
|
||||||
|
console.log('执行消息播报');
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
wxTextToSpeach(content.msg)
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
baiduyy(content.msg)
|
||||||
|
// #endif
|
||||||
|
uni.vibrateLong({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default model
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import {
|
||||||
|
$pushInfoRegister
|
||||||
|
} from '@/http/apiManager.js'
|
||||||
|
import storageManage from '@/commons/utils/storageManage.js'
|
||||||
|
// 默认导出 方法 注册 push连接
|
||||||
|
export default async function() {
|
||||||
|
let cid1 = undefined // unipush1.0 客户端CID
|
||||||
|
let cid2 = undefined // unipush2.0 客户端CID
|
||||||
|
let orgCid = undefined // 原始cid如果获取的cid和新的cid不相同赋值原始cid后端会根据原始cid更新
|
||||||
|
let cidType = undefined //传递类型 是 app 还是 微信
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
cidType = 'app_plus'
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
cidType = 'mp_weixin'
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
if (!plus) {
|
||||||
|
cid1 = plus.push.getClientInfo().clientid
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
const data = await uni.getPushClientId()
|
||||||
|
console.log('客户端推送标识:', data.cid)
|
||||||
|
cid2 = data.cid
|
||||||
|
// 如果不存 cid 本地存储 写入 cid
|
||||||
|
if (!storageManage.uniPush2Cid()) {
|
||||||
|
storageManage.uniPush2Cid(data.cid)
|
||||||
|
} else if (cid2 !== storageManage.uniPush2Cid()) { // 否则进行 cid 对比 判断 是否相等 不相等 赋值 orgCid
|
||||||
|
orgCid = storageManage.uniPush2Cid() //赋值原始cid
|
||||||
|
storageManage.uniPush2Cid(data.cid) //重新写入 cid
|
||||||
|
}
|
||||||
|
if (cid1) {
|
||||||
|
pushInfoRegister(cid1)
|
||||||
|
} else {
|
||||||
|
pushInfoRegister(cid1, cid2, orgCid, cidType)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushInfoRegister(cid1 = '', cid2 = '', org = '', cidType = '') {
|
||||||
|
$pushInfoRegister({
|
||||||
|
cid1,
|
||||||
|
cid2,
|
||||||
|
orgCid: org,
|
||||||
|
cidType
|
||||||
|
}).then(res => {
|
||||||
|
orgCid = '' //重置 数据
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { $mchConfig } from "@/http/apiManager"
|
||||||
|
import storageManage from '@/commons/utils/storageManage.js'
|
||||||
|
let num = 0 //计算错误此时 超过5次错误 不在出触发
|
||||||
|
const plugin = requirePlugin("WechatSI")
|
||||||
|
const pushMsgArr = [] //维护一个消息队列
|
||||||
|
let backgroundAudioManager = undefined //获取背景音频实例
|
||||||
|
let audioMp3 = ''
|
||||||
|
console.log('执行创建 语音播报逻辑');
|
||||||
|
// 获取配置项 判断是否 开启 小程序 语音推送
|
||||||
|
export function getPushStatus () {
|
||||||
|
if (!storageManage.token()) return //未登录 不播放
|
||||||
|
$mchConfig('orderConfig').then(({ bizData = [] }) => {
|
||||||
|
const weChat = bizData.find(v => v.configKey == "weChatVoice")
|
||||||
|
if (weChat && weChat?.configVal == 1) {
|
||||||
|
createBgMusice()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// getPushStatus()
|
||||||
|
// 创建 背景音乐
|
||||||
|
function createBgMusice (file) {
|
||||||
|
backgroundAudioManager = wx.getBackgroundAudioManager()
|
||||||
|
backgroundAudioManager.title = '订单通知'
|
||||||
|
if (!audioMp3) {
|
||||||
|
createFile()
|
||||||
|
} else {
|
||||||
|
backgroundAudioManager.src = audioMp3
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听 音频播放失败事件
|
||||||
|
backgroundAudioManager.onError(function (res) {
|
||||||
|
console.log('音频播放失败', res, num);
|
||||||
|
if (num >= 5) return
|
||||||
|
createFile()
|
||||||
|
num++
|
||||||
|
})
|
||||||
|
// 监听 音频播放结束事件
|
||||||
|
onBgMusiceEnd()
|
||||||
|
}
|
||||||
|
// 监听bei背景音乐播放状态
|
||||||
|
export function onBgMusiceEnd () {
|
||||||
|
backgroundAudioManager.onEnded(() => {
|
||||||
|
if (pushMsgArr.length > 0) return broadcast(pushMsgArr.pop()) //如果有消息 则继续播放
|
||||||
|
backgroundAudioManager.src = audioMp3 //否则播放默认背景音乐
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function startOrEndMusice (flag) {
|
||||||
|
if (!flag && !!backgroundAudioManager) return backgroundAudioManager.stop() //关闭背景音乐 地址指向空即可
|
||||||
|
if (!backgroundAudioManager) return createBgMusice() // 如果一开始是关闭状态 则创建背景音乐实例
|
||||||
|
backgroundAudioManager.src = audioMp3 // 否则重新赋值背景音地址即可
|
||||||
|
}
|
||||||
|
export default function (message) {
|
||||||
|
if (!backgroundAudioManager) return
|
||||||
|
pushMsgArr.unshift(message) //将消息添加到消息队列头部 背景音乐播放结束后 会对消息队列 进行校验 如果消息队列有消息 会进行播放 否则继续循环背景音乐
|
||||||
|
}
|
||||||
|
// 播放订单
|
||||||
|
function broadcast (msg) {
|
||||||
|
plugin.textToSpeech({
|
||||||
|
lang: "zh_CN",
|
||||||
|
tts: true,
|
||||||
|
content: msg,
|
||||||
|
success: function (res) {
|
||||||
|
backgroundAudioManager.src = res.filename;
|
||||||
|
onBgMusiceEnd()
|
||||||
|
},
|
||||||
|
fail: function (res) {
|
||||||
|
console.log("fail tts", res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建文件
|
||||||
|
export function createFile (file) {
|
||||||
|
const fs = wx.getFileSystemManager()
|
||||||
|
fs.copyFile({
|
||||||
|
srcPath: `static/noiseless.mp3`,
|
||||||
|
destPath: `${wx.env.USER_DATA_PATH}/noiseless.mp3`,
|
||||||
|
success (res) {
|
||||||
|
console.log(res, `${wx.env.USER_DATA_PATH}/noiseless.mp3`)
|
||||||
|
audioMp3 = `${wx.env.USER_DATA_PATH}/noiseless.mp3`
|
||||||
|
backgroundAudioManager.src = audioMp3
|
||||||
|
},
|
||||||
|
fail (res) {
|
||||||
|
console.error(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
创建 云空间 上传云函数 云函数 url化 运营平台 配置云函数地址
|
||||||
|
|
||||||
|
打包时 勾选云push 2.0 push1.0 仅支持 app 推送
|
||||||
|
|
||||||
|
注意配置 百度语音相关参数
|
||||||
|
|
||||||
|
使用push2.0 请将 static\noiseless.mp3 文件 配置到运营平台 系统 配置 通知配置 push2.0 uniPush语音播报音频文件(小程序播报必填) 下
|
||||||
|
|
||||||
|
注意:扩展库依赖3张opendb表:opendb-tempdata,opendb-device,uni-id-device。公测版uniCloud,执行扩展库会自动创建。如果你使用的是uniCloud正式版需要自己创建这3张表。
|
||||||
|
|
||||||
|
|
@ -15,13 +15,7 @@ const appConfig = {
|
||||||
DEVELOPMENT: 'development', // 本地调试地址
|
DEVELOPMENT: 'development', // 本地调试地址
|
||||||
TEST: 'test', // 测试地址
|
TEST: 'test', // 测试地址
|
||||||
DEMO: 'demo', // 演示环境
|
DEMO: 'demo', // 演示环境
|
||||||
PRODUCTION: 'production' ,// 生产环境,
|
PRODUCTION: 'production' // 生产环境
|
||||||
// # 测试
|
|
||||||
// VITE_API_URL: 'https://cashier-client.sxczgkj.cn/cashier-client',
|
|
||||||
// # 预发布
|
|
||||||
VITE_API_URL: 'https://pre-cashierclient.sxczgkj.cn/cashier-client',
|
|
||||||
// # 线上环境接口地址
|
|
||||||
// VITE_API_URL: 'https://cashierclient.sxczgkj.cn/cashier-client',
|
|
||||||
},
|
},
|
||||||
|
|
||||||
storeEnvEnumKey: 'currentEnvEnum', // 本地存储的envkey的值
|
storeEnvEnumKey: 'currentEnvEnum', // 本地存储的envkey的值
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
},
|
},
|
||||||
"router" : {
|
"router" : {
|
||||||
"mode" : "history", //采用history模式URL的路径才跟配置的对应上,不然URL是先加/#再追加配置的地
|
"mode" : "history", //采用history模式URL的路径才跟配置的对应上,不然URL是先加/#再追加配置的地
|
||||||
"base" : "/pay_pre" //在页面路由上加上该前缀
|
"base" : "/pay" //在页面路由上加上该前缀
|
||||||
},
|
},
|
||||||
"devServer" : {
|
"devServer" : {
|
||||||
"port" : 80,
|
"port" : 80,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<view class="info">
|
<view class="info">
|
||||||
<image class="shopImage" :src="shopImage" mode="aspectFill"></image>
|
<image class="shopImage" :src="shopImage"></image>
|
||||||
<view class="shopName">{{shopName}}</view>
|
<view class="shopName">{{shopName}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="input">
|
<view class="input">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue