This commit is contained in:
2024-09-10 10:49:08 +08:00
parent b5fd06b800
commit dd4f5938da
6391 changed files with 722800 additions and 0 deletions

1
commons/JSON/mccAli.json Normal file

File diff suppressed because one or more lines are too long

7
commons/color.js Normal file
View File

@@ -0,0 +1,7 @@
export const ColorMain= '#318AFE';
export const ColorRed= '#F02C45';
export default{
ColorMain,ColorRed
}

14
commons/readme.txt Normal file
View File

@@ -0,0 +1,14 @@
该文件夹内放置: 项目自建资源, 比如 公共样式文件, 和 工具包等文件。
目录结构:
commons
style
utils
知识点: 样式文件不应该放置到 static文件夹内css、less/scss 等资源不要放在 static 目录下,建议这些公用的资源放在自建的 common 目录下。), 详见:
https://uniapp.dcloud.net.cn/tutorial/project.html

378
commons/style/common.scss Normal file
View File

@@ -0,0 +1,378 @@
.u-relative,
.u-rela {
position: relative;
}
.u-absolute,
.u-abso {
position: absolute;
}
.u-fixed,.u-fix{
position: fixed;
}
.left-top{
left: 0;
top: 0;
}
.u-overflow-hide{
overflow: hidden;
}
// nvue不能用标签命名样式不能放在微信组件中否则微信开发工具会报警告无法使用标签名当做选择器
/* #ifndef APP-NVUE */
image {
display: inline-block;
}
// 在weex也即nvue中所有元素默认为border-box
view,
text {
box-sizing: border-box;
}
/* #endif */
.u-font-xs {
font-size: 22rpx;
}
.u-font-sm {
font-size: 26rpx;
}
.u-font-md {
font-size: 28rpx;
}
.u-font-lg {
font-size: 30rpx;
}
.u-font-xl {
font-size: 34rpx;
}
.u-flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.u-flex-wrap {
flex-wrap: wrap;
}
.u-flex-nowrap {
flex-wrap: nowrap;
}
.u-col-center {
align-items: center;
}
.u-col-top {
align-items: flex-start;
}
.u-col-bottom {
align-items: flex-end;
}
.u-row-center {
justify-content: center;
}
.u-row-left {
justify-content: flex-start;
}
.u-row-right {
justify-content: flex-end;
}
.u-row-between {
justify-content: space-between;
}
.u-row-around {
justify-content: space-around;
}
.u-text-left {
text-align: left;
}
.u-text-center {
text-align: center;
}
.u-text-right {
text-align: right;
}
.u-flex-col {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
// 定义flex等分
@for $i from 0 through 12 {
.u-flex-#{$i} {
flex: $i;
}
}
// 定义字体(px)单位小于20都为px单位字体
@for $i from 9 to 20 {
.u-font-#{$i} {
font-size: $i + px;
}
}
// 定义字体(rpx)单位大于或等于20的都为rpx单位字体
@for $i from 20 through 40 {
.u-font-#{$i} {
font-size: $i + rpx;
}
}
// 定义内外边距历遍1-80
@for $i from 0 through 80 {
// 只要双数和能被5除尽的数
@if $i % 2 == 0 or $i % 5 == 0 {
// 得出u-margin-30或者u-m-30
.u-margin-#{$i}, .u-m-#{$i} {
margin: $i + rpx!important;
}
// 得出u-padding-30或者u-p-30
.u-padding-#{$i}, .u-p-#{$i} {
padding: $i + rpx!important;
}
@each $short, $long in l left, t top, r right, b bottom {
// 缩写版,结果如: u-m-l-30
// 定义外边距
.u-m-#{$short}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-p-#{$short}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
// 完整版结果如u-margin-left-30
// 定义外边距
.u-margin-#{$long}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-padding-#{$long}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
}
}
}
// 重置nvue的默认关于flex的样式
.u-reset-nvue {
flex-direction: row;
align-items: center;
}
/* start--文本行数限制--start */
.u-line-1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.u-line-2 {
-webkit-line-clamp: 2;
}
.u-line-3 {
-webkit-line-clamp: 3;
}
.u-line-4 {
-webkit-line-clamp: 4;
}
.u-line-5 {
-webkit-line-clamp: 5;
}
.u-line-2, .u-line-3, .u-line-4, .u-line-5 {
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box; // 弹性伸缩盒
-webkit-box-orient: vertical; // 设置伸缩盒子元素排列方式
}
/* end--文本行数限制--end */
/* start--不同颜色文字--start */
.color-333{
color: #333;
}
.color-666{
color: #666;
}
.color-999{
color: #999;
}
.color-red{
color: $my-red-color;
}
.color-main{
color:$my-main-color
}
/* end--不同颜色文字--end */
.tranistion{
transition: all .3s ease-in-out;
}
.tranistion-1{
transition: all .1s ease-in-out;
}
.tranistion-2{
transition: all .2s ease-in-out;
}
.font-bold{
font-weight: 700;
}
/* start--不同颜色背景--start */
.my-bg-main{
background-color:$my-main-color
}
/* end--不同颜色背景--end */
.safe-page{
padding-bottom: 60rpx!important;
}
::v-deep .uni-switch-input.uni-switch-input-checked{
border-color: $my-main-color;
background-color: $my-main-color;
}
.min-page{
/* #ifdef H5 */
min-height: calc(100vh - 44px);
/* #endif */
/* #ifndef H5 */
min-height: 100vh;
/* #endif */
}
.w-full{
width: 100%;
}
.gap-20{
gap: 20rpx;
}
.color-000{
color: #000;
}
.color-fff{
color: #fff;
}
.bg-fff{
background-color: #fff;
}
.bg-gray{
background-color: #F9F9F9;
}
.overflow-hide{
/* #ifdef H5 */
height: calc(100vh - 44px);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
overflow: hidden;
}
.no-wrap{
white-space: nowrap;
}
.border-r-12{
border-radius: 12rpx;
}
.border-r-18{
border-radius: 18rpx;
}
.border-top{
border-top: 1px solid #E5E5E5;
}
.border-bottom{
border-bottom: 1px solid #E5E5E5;
}
.scale7{
transform: scale(0.7);
}
.page-gray {
min-height: calc(100vh);
/* #ifdef H5 */
min-height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
background: #F9F9F9;
}
.safe-bottom{
padding-bottom: env(safe-area-inset-bottom);
/* #ifdef H5 */
padding-bottom: 28rpx;
/* #endif */
}
.position-all{
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.fixed-top{
position: fixed;
/* #ifdef H5 */
top: 44px;
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
left: 0;
right: 0;
}
.lh30 {
line-height: 30px;
}
.default-box-padding{
padding: 32rpx 28rpx;
}
.icon-arrow-down-fill {
width: 16rpx;
height: 10rpx;
}
.zIndex-999{
z-index: 999;
}
.icon-default-size{
width: 28rpx;
height: 28rpx;
}
::v-deep.uni-easyinput__placeholder-class{
font-size: 28rpx!important;
}
.filter-gray{
filter: grayscale(1);
}

230
commons/style/global.scss Normal file
View File

@@ -0,0 +1,230 @@
/**
* 系统级别: 全局样式
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
/** 已整理 **/
// 通用 列表页样式
.page-wrapper {
min-height: calc(100vh - 70rpx); /** 最小高度 **/
padding-bottom: 70rpx; /** 安全距离防止home条遮挡文字 **/
background-color: $v-color-bgrey; /** 全局背景灰 **/
}
// 底部 固定的按钮, 比如: 创建门店, 创建员工等按钮。
.list-footer{
height: 100rpx;
background: transparent;
.button-wrapper {
border-top: 1rpx solid rgba(0,0,0, 0.07);
background-color: rgba(252, 252, 252, 0.85);
backdrop-filter: blur(20rpx);
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 30rpx;
}
}
/** 详情页 覆写list-item */
.list-item-by-detail {
padding: 60rpx 60rpx 10rpx 60rpx !important;
background-color: transparent !important; /** 背景透明 **/
.list-title{
color: #fff !important;
}
.list-subtitle{
color: rgba(251,252,253,0.7) !important;
}
.list-info {
image {
margin-right: 0 !important;
}
}
}
/**列表条目渲染, 比如: 头像、 主标题, **/
.list-item {
display: flex;
align-items: center;
padding: 0 40rpx;
height: 170rpx;
background-color: #FFF; /** 背景 白色 **/
image {
flex-shrink: 0;
flex-grow: 0;
width: 100rpx;
height: 100rpx;
margin-right: 30rpx;
}
.list-info {
flex: 1;
.list-title {
display: flex;
justify-content: space-between;
align-items: center;
height: 40rpx;
color: rgba(77,77,77,1);
.list-name {
width: auto;
flex: 1;
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 400;
}
}
.list-subtitle {
color: rgba(153, 153, 153, 1);
margin-top: 25rpx;
font-size: 26rpx;
font-weight: 400;
width: 430rpx;
}
}
}
/** 状态小圆点 **/
.state-dot {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 400;
&::after {
content: '';
display: block;
margin-left: 20rpx;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
}
}
/** 状态小圆点 **/
.state-dot-enable {
&::after {
background-color: #168FFF;
}
}
/** 状态小圆点 **/
.state-dot-disable {
&::after {
background-color: #D9D9D9;
}
}
/** 状态小圆点 **/
.state-dot-error {
&::after {
background-color: red;
}
}
/**
* 描述预览图, 参考: app详情
* 第一个最后一个距离上下 40rpx, 中间间距20rpx
*/
.desc-view {
.desc-view-item {
display: flex;
justify-content: space-between;
padding: 20rpx 40rpx;
font-size: 30rpx;
font-weight: 400;
.title {
color: #808080;
}
.desc {
color: #000;
}
&:first-child {
margin-top: 20rpx;
}
&:last-child {
margin-bottom: 20rpx;
}
}
}
/** 已整理 **/
//容器内部元素上下左右居中
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 触摸反馈样式
.touch-hover {
background-color: #f7f8fa !important ;
}
.touch-button {
opacity: 0.5;
}
/* 单行文本超出省略号 */
.single-text-beyond {
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*禁止换行*/
text-overflow: ellipsis; /*省略号*/
}
// 按钮背景样式
.footer-button-style {
border-top: 1rpx solid #fcfcfc;
background-color: rgba(252, 252, 252, 0.85);
backdrop-filter: blur(20rpx);
}
// 搜素框 提示语样式
.input-placeholder {
font-size: 32rpx;
color: rgba(0, 0, 0, 0.35);
}
// 表单分割线
.line {
height: 20rpx;
background-color: $v-color-bgrey;
}
/**
* jeepay-btn 通用btn样式。
* 用法: <button class='jeepay-btn' hover-class="hover-button" @tap="loginFunc">登录</button>
*/
.jeepay-btn {
display: flex;
justify-content: center;
align-items: center;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: $J-color-tff;
border-radius: 20rpx;
background: linear-gradient(270deg, rgba(35,143,252,1) 0%, rgba(26,102,255,1) 100%);
box-shadow: 0 20rpx 60rpx -20rpx rgba(0,84,210,0.5);
&.hover-button {
opacity: 0.5;
}
}
/** 输入框icon **/
.input-icon{
width: 36rpx;
height: 36rpx;
}

View File

@@ -0,0 +1,181 @@
/**
* 系统级别:覆写 uni样式
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
/* 去除开关右侧边距 */
.uni-switch-input {
margin-right: 0 !important;
}
/* .uni-navbar {
position: relative;
z-index: 10;
} */
.uni-popup{
z-index: 998 !important;
}
// 表单组件样式 覆写
.uni-forms-item {
display: flex;
align-items: center;
min-height: 120rpx;
background-color: $J-bg-ff;
font-size: 32rpx;
font-weight: 400;
}
.uni-forms-item ::v-deep .uni-forms-item__label {
font-size: 32rpx !important;
font-weight: 400;
text-indent: 40rpx;
color: #4d4d4d;
height: auto !important;
}
// uni-form-item 表单校验, 如果校验不通过, 显示的文字占位, 并且添加下边距。
.uni-forms-item__error.msg--active{
position: relative !important;
margin-bottom: 30rpx;
}
.is-input-error-border .uni-easyinput__placeholder-class{
color: #f56c6c !important
}
// 去掉按钮边框
button:after {
border: none !important;
}
// 去点导航栏组件center&right
::v-deep.uni-navbar__header {
.uni-navbar__header-container,
.uni-navbar__header-btns-right {
display: none !important;
}
}
// 修改 uuni-easyinput
// form 外层必须包裹一个 view class="jeepay-form"
.jeepay-form {
.uni-easyinput {
.uni-easyinput__content {
border: 2px solid transparent !important;
height: 110rpx;
padding: 0 30rpx;
margin-bottom: 50rpx;
box-sizing: border-box !important;
border-radius: 20rpx !important;
background-color: rgba(247, 247, 247, 1) !important;
}
.uni-easyinput__content-input {
color: rgba(0, 0, 0, 1);
font-size: 32rpx !important;
font-weight: 400;
}
.is-foucs {
border: 2px solid #1d79fd !important;
background-color: white !important;
}
.uni-input-placeholder
/* #ifdef MP-WEIXIN */
,.uni-easyinput__placeholder-class
/* #endif */ {
font-size: 32rpx !important;
color: #B3B3B3 !important;
}
}
}
.jeepay-edit-form .uni-easyinput__content-input {
padding-left: 0 !important;
.uni-input-placeholder {
font-size: 32rpx !important;
}
}
// 设置新密码覆盖form默认样式
.new-password {
.uni-forms-item.is-direction-left {
padding: 0 40rpx;
.uni-forms-item__label {
width: 190rpx !important;
font-size: 32rpx !important;
font-weight: 400;
white-space: nowrap;
color: rgba(102, 102, 102, 1);
text-indent: 0 !important;
}
.uni-easyinput__placeholder-class {
font-size: 32rpx !important;
font-weight: 400 !important;
}
}
}
// 搜索栏覆盖默认样式
/* #ifdef MP-WEIXIN */
.input-main {
button {
font-size: 32rpx;
color: rgba(29,121,253,1);
background: rgba(255,255,255,1);
}
.uni-easyinput {
.uni-easyinput__content {
background-color: $J-bg-f5 !important;
border-radius: $J-b-r12;
.uni-easyinput__content-input {
padding-left: 0 !important;
.uni-input-input {
border-radius: $J-b-r12 !important;
overflow: hidden !important;
}
}
.uni-input-placeholder {
font-size: 27rpx;
}
.uni-icons {
color: rgba(230,230,230,1) !important;
}
}
}
}
/* #endif */
// 搜索栏覆盖默认样式
/* #ifdef MP-WEIXIN */
button[is="components/Button/Button"] {
padding: 0;
background-color: transparent !important;
}
/* #endif */
// 修改时间选择器按钮颜色
.xp-button--confirm {
background: $jeepay-bg-primary;
}
.xp-button--cancel {
color: rgba(0, 0, 0, 0.5) !important;
}
// label 样式
.f-label{
width: 280rpx;
align-self: start;
padding-top: 40rpx;
font-size: 32rpx ;
font-weight: 400;
text-indent: 40rpx;
color: #4d4d4d;
}

77
commons/style/vars.scss Normal file
View File

@@ -0,0 +1,77 @@
/**
* 系统级别: 自定义变量
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
// $v : 表示: variables简写。 uni的默认都有特殊开头 一般不会重复。
$v-color-t21: #217dfe;
// 全局通用: 背景灰 background grey
$v-color-bgrey: #F7F7F7;
// 背景色
$J-bg-f7: #f7f7f7; //页面背景色
$J-bg-ff: #fff;
$J-bg-f5: #f5f5f5; //输入框背景色
// 文字颜色
$J-color-t80: #808080; //常用于 未选中文字颜色
$J-color-t21: #217dfe; //卡片文字选中 统计报表
$J-color-tff: #fff;
$J-color-tSff: rgba(255, 255, 255, 0.7);
$J-color-t29: #2980fd; //选中 文字颜色 搜索
$J-color-ta6: #a6a6a6;
$J-color-t4d: #4d4d4d; //标题颜色
$J-color-t99: #999;
$J-color-t8c: #8c8c8c; // 卡片列表 标题文字颜色
//圆角相关变量
$J-b-r32: 32rpx;
$J-b-r12: 12rpx;
$J-b-r10: 10rpx;
$v-b-r20: 20rpx;
// 文字大小
$J-f-size30: 30rpx;
// 常用边框颜色
$v-b-color-ed: #ededed;
//common.scss 分包页面以及组件里所用的颜色
$my-main-color:#318AFE;
$my-red-color:#F02C45;
//my-components
$u-main-color: #303133;
$u-content-color: #606266;
$u-tips-color: #909193;
$u-light-color: #c0c4cc;
$u-border-color: #dadbde;
$u-bg-color: #f3f4f6;
$u-disabled-color: #c8c9cc;
$u-primary: #3c9cff;
$u-primary-dark: #398ade;
$u-primary-disabled: #9acafc;
$u-primary-light: #ecf5ff;
$u-warning: #f9ae3d;
$u-warning-dark: #f1a532;
$u-warning-disabled: #f9d39b;
$u-warning-light: #fdf6ec;
$u-success: #5ac725;
$u-success-dark: #53c21d;
$u-success-disabled: #a9e08f;
$u-success-light: #f5fff0;
$u-error: #f56c6c;
$u-error-dark: #e45656;
$u-error-disabled: #f7b2b2;
$u-error-light: #fef0f0;
$u-info: #909399;
$u-info-dark: #767a82;
$u-info-disabled: #c4c6c9;
$u-info-light: #f4f4f5;

30
commons/table-status.js Normal file
View File

@@ -0,0 +1,30 @@
export const $status = {
pending: {
label: "挂单中",
type: "#E6A23C",
},
using: {
label: "开台中",
type: "rgb(250,85,85)",
},
paying: {
label: "结算中",
type: "#E6A23C",
},
idle: {
label: "空闲",
type: "#318AFE",
},
subscribe: {
label: "预定",
type: "#E6A23C",
},
closed: {
label: "关台",
type: "#ddd",
},
cleaning: {
label: "台桌清理中",
type: "#909399",
},
}

0
commons/utils/.keep Normal file
View File

28
commons/utils/ak.js Normal file
View File

@@ -0,0 +1,28 @@
/**
* 统一工具类 (all utils x ) aux ( 谐音 ) [ window 无法创建此命名的文件 放弃。 = = ]
* 统一使用: all Kit 简称 ak.
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/12/12 18:38
*/
import go from './go.js'
import emit from './emit.js'
import ent from './ent.js'
import cal from './cal.js'
import dataKit from './dataKit.js'
import timer from './timer.js'
import infoBox from './infoBox.js'
const ak = {
go: go,
emit: emit,
ent: ent,
cal: cal,
timer: timer,
infoBox: infoBox,
}
export default ak

37
commons/utils/cal.js Normal file
View File

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

38
commons/utils/dataKit.js Normal file
View File

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

164
commons/utils/datamap.js Normal file
View File

@@ -0,0 +1,164 @@
/**
* datamap , 数据字典, 存放常用的配置常量信息。 如订单类型的判断, 用户类型的判断。
*
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/28 16:16
*/
const payOrderStateMap = {
0: {
text: '订单生成',
color: '#2980FD'
},
1: {
text: '支付中',
color: '#FFAA33'
},
2: {
text: '支付成功',
color: '#09BB07'
},
3: {
text: '支付失败',
color: '#CB2972'
},
4: {
text: '已撤销',
color: '#808080'
},
5: {
text: '已退款',
color: '#FF5B4C'
},
6: {
text: '订单关闭',
color: '#D9D9D9'
},
}
// 订单 图片 和背景颜色
const payOrderImageMap = {
WECHAT: {
title: '微信',
imgUrl: '/static/orderImg/wechat.svg', //微信支付
bgColor: '#09BB07',
},
ALIPAY: {
title: '支付宝',
imgUrl: '/static/orderImg/zfb.svg', //支付宝支付
bgColor: '#458FFF',
},
YSFPAY: {
title: '云闪付',
imgUrl: '/static/orderImg/ysf.svg', // 云闪付支付
bgColor: '#FF5B4C',
},
UNIONPAY: {
title: '银联',
imgUrl: '/static/orderImg/union-pay.svg', //银联支付
bgColor: '#0D131A',
},
OTHER: {
title: '其他',
imgUrl: '/static/orderImg/default-pay.svg', //其他支付
bgColor: '#5F36C4',
},
}
// 1-超级管理员 2-普通用户 3-拓展员, 11-店长, 12-店员
const userTypeMap = {
1: {
text: '超管',
bgColor: 'linear-gradient(270deg, rgba(35,161,252,1) 0%, rgba(26,102,255,1) 100%)',
type: 'blue'
},
2: {
text: '普通用户',
bgColor: 'linear-gradient(270deg, rgba(35,161,252,1) 0%, rgba(26,102,255,1) 100%)'
},
3: {
text: '拓展员',
bgColor: 'linear-gradient(270deg, rgba(35,161,252,1) 0%, rgba(26,102,255,1) 100%)'
},
11: {
text: '店长',
bgColor: 'linear-gradient(270deg, rgba(220,61,138,1) 0%, rgba(187,23,92,1) 100%)',
type: 'purple'
},
12: {
text: '店员',
bgColor: ' linear-gradient(270deg, rgba(61,220,68,1) 0%, rgba(23,187,118,1) 100%)',
type: 'green'
},
}
// 设备厂商
const devProvider = {
zgwl: '智谷物联',
bsj: '博实结',
fe: '飞鹅',
ps: '品生',
clj: '财来聚',
wsy: '微收银',
xjl: '小精灵',
lmspay: '立码收',
lkls: '拉卡拉',
zw: '智网'
}
const rechargeStateMap = {
0: {
text: '初始化',
color: '#2980FD'
},
1: {
text: '充值中',
color: '#FFAA33'
},
2: {
text: '充值成功',
color: '#09BB07'
},
3: {
text: '充值失败',
color: '#CB2972'
}
}
const model = {
// 订单状态文本和color
payOrderState: (state) => {
// 避免循环判断,影响性能。
if (payOrderStateMap[state]) {
return payOrderStateMap[state]
}
return {
text: '未知',
color: '#D9D9D9'
}
},
// 订单图片 和图片背景颜色
payOrderImage: (state) => {
// 取值 找到 返回当前值 未找到返回空对象
return payOrderImageMap[state] || {}
},
// 用户类型的判断
userType: (userTypeVal) => {
return userTypeMap[userTypeVal] || {}
},
// 查找设备厂商 找到就返回 找不到据返回空
provider: (state) => {
return devProvider[state] || '未知'
},
// 会员充值订单图片 和图片背景颜色
rechargeRecordImage: (state) => {
// 取值 找到 返回当前值 未找到返回空对象
return rechargeStateMap[state] || {}
},
}
export default model

138
commons/utils/emit.js Normal file
View File

@@ -0,0 +1,138 @@
/**
* 页面通讯工具类uni.emit的封装
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/11/24 15:54
*/
const model = {
// 定义监听器的名字, 应该是一个页面一个, 不可两个页面公共一个, 否则会导致: 一个页面onUnload 移除时影响另一个页面的正常接收。
// 业务页面 监听, onUnload应该移除掉。
// 通用搜索页
ENAME_REF_SEARCH_PAGE : 'ENAME_REF_SEARCH_PAGE',
// 应用列表页的刷新
ENAME_REF_TABLE_MCH_APP : 'ENAME_REF_TABLE_MCH_APP',
// 应用详情
ENAME_REF_TABLE_MCH_APP_DETAILS : 'ENAME_REF_TABLE_MCH_APP_DETAILS',
// 调起扫一扫
ENAME_E_PAY_SCAN : 'ENAME_E_PAY_SCAN',
// 重置 金额
ENAME_RESET_PAY_AMOUNT: 'ENAME_RESET_PAY_AMOUNT',
// 更新支付订单信息
ENAME_REF_PAY_ORDER : 'ENAME_REF_PAY_ORDER',
// 更新 门店列表
ENAME_REF_STORE_LIST : 'ENAME_REF_STORE_LIST',
// 更新 门店详情
ENAME_REF_STORE_DETAIL : 'ENAME_REF_STORE_DETAIL',
// 更新 员工列表
ENAME_REF_SYS_USER_LIST : 'ENAME_REF_SYS_USER_LIST',
// 更新 员工详情
ENAME_REF_SYS_USER_DETAIL : 'ENAME_REF_SYS_USER_DETAIL',
// 更新 通道列表
ENAME_REF_PAY_PASSAGE_LIST : 'ENAME_REF_PAY_PASSAGE_LIST',
// 更新 辅助终端信息
ENAME_REF_TERMINAL_LIST : 'ENAME_REF_TERMINAL_LIST',
// 更新 辅助终端 详情页
ENAME_REF_TERMINAL_DETAIL : 'ENAME_REF_TERMINAL_DETAIL',
// 更新 智能pos 信息
ENAME_REF_AUTOPOS_LIST : 'ENAME_REF_AUTOPOS_LIST',
// 更新 智能pos 详情页
ENAME_REF_AUTOPOS_DETAIL : 'ENAME_REF_AUTOPOS_DETAIL',
// 更新 扫码pos 信息
ENAME_REF_SCANPOS_LIST : 'ENAME_REF_SCANPOS_LIST',
// 更新 扫码pos 详情页
ENAME_REF_SCANPOS_DETAIL : 'ENAME_REF_SCANPOS_DETAIL',
// 码牌列表
ENAME_REF_QRC_LIST : 'ENAME_REF_QRC_LIST',
// 码牌详情
ENAME_REF_QRC_DETAIL : 'ENAME_REF_QRC_DETAIL',
// 更新 打印机 信息
ENAME_REF_PRINTER_LIST : 'ENAME_REF_PRINTER_LIST',
// 更新 打印机 详情页
ENAME_REF_PRINTER_DETAIL : 'ENAME_REF_PRINTER_DETAIL',
// 云喇叭列表
ENAME_REF_SPEAKER_LIST : 'ENAME_REF_SPEAKER_LIST',
// 云喇叭详情
ENAME_REF_SPEAKER_DETAIL : 'ENAME_REF_SPEAKER_DETAIL',
// 进件列表
ENAME_REF_APPLYMENT_LIST : 'ENAME_REF_APPLYMENT_LIST',
// 刷脸设备列表
ENAME_REF_FACE_LIST : 'ENAME_REF_FACE_LIST',
// 刷脸设备详情
ENAME_REF_FACE_DETAIL : 'ENAME_REF_FACE_DETAIL',
// 刷脸广告列表
ENAME_REF_AD_LIST : 'ENAME_REF_AD_LIST',
// 刷脸广告 详情
ENAME_REF_AD_DETAILS : 'ENAME_REF_AD_DETAILS',
// 更新 会员列表
ENAME_REF_MEMBER_LIST : 'ENAME_REF_MEMBER_LIST',
// 更新 会员详情
ENAME_REF_MEMBER_DETAIL : 'ENAME_REF_MEMBER_DETAIL',
// 更新 会员账户流水列表
ENAME_REF_MEMBER_ACCOUNT_HISTORY_LIST : 'ENAME_REF_MEMBER_ACCOUNT_HISTORY_LIST',
// 更新 会员账户流水详情
ENAME_REF_MEMBER_ACCOUNT_HISTORY_DETAIL : 'ENAME_REF_MEMBER_ACCOUNT_HISTORY_DETAIL',
// 更新 会员充值记录列表
ENAME_REF_MEMBER_RECHARGE_RECORD_LIST : 'ENAME_REF_MEMBER_RECHARGE_RECORD_LIST',
// 更新 会员充值记录详情
ENAME_REF_MEMBER_RECHARGE_RECORD_DETAIL : 'ENAME_REF_MEMBER_RECHARGE_RECORD_DETAIL',
// 更新 充值规则列表
ENAME_REF_RECHARGE_RULE_LIST : 'ENAME_REF_RECHARGE_RULE_LIST',
// 刷新页面的 发射事件 , 更新页面 && 更新搜索页面
refPageAndSearchEmit: (refEmitEventName, data = {} ) => {
model.pageEmit(refEmitEventName, data)
model.pageEmit(model.ENAME_REF_SEARCH_PAGE, data)
},
// 自定义
pageEmit: (refEmitEventName, data) => {
uni.$emit(refEmitEventName, data )
},
// 废弃该函数。 ( 因为: 页面只监听一次, 使用该函数则无法再次监听, 需要再每个页面写入: uni.$on 保证正常接收。 )
// 监听页面刷新函数
on: (refEmitEventName) => {
return new Promise( (resolve) => {
uni.$on(refEmitEventName, function(data){
resolve( data )
})
})
}
}
export default model

View File

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

21
commons/utils/ent.js Normal file
View File

@@ -0,0 +1,21 @@
/**
* 权限判断
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/11/22 14:29
*/
import storageManage from '@/commons/utils/storageManage.js'
const model = {
// 判断是否包含该权限
has(entId){
let userInfo = storageManage.userInfo()
if(userInfo && userInfo.entIdList && userInfo.entIdList.indexOf(entId) >= 0){
return true;
}
return false;
}
}
export default model

101
commons/utils/formUtil.js Normal file
View File

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

54
commons/utils/format.js Normal file
View File

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

View File

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

View File

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

109
commons/utils/go.js Normal file
View File

@@ -0,0 +1,109 @@
/**
* 页面跳转工具类
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/11/14 17:12
*/
// 引入 pages用于解析 pageId 变量 , 注意 需要在 pages.json 定义pageId 参数。
// 使用方法: go.to(""), 优点: 扩展分包可任意路径业务调用不再传入固定URL, 传入的是pageId变量。
import pagesJSON from '@/pages.json'
import emit from './emit.js'
// 获取到全部的页面路径 和 ID
const ALL_PAGES = { }
// 添加到 ALL_PAGES
function addPages(pagesRoot){
let rootUrl = pagesRoot.root ? `/${pagesRoot.root}/` : '/'
pagesRoot.pages.forEach(r => {
if(r.pageId){
ALL_PAGES[r.pageId] = rootUrl + r.path
}
})
}
// 1. 添加 主目录
addPages(pagesJSON)
// 2. 添加分包文件 目录
if(pagesJSON.subPackages){
pagesJSON.subPackages.forEach(r => addPages(r))
}
const model = {
// 跳转类型
GO_TYPE_TO: 'navigateTo',
GO_TYPE_REDIRECT: 'redirect',
GO_TYPE_RELAUNCH: 'reLaunch',
GO_TYPE_SWITCHTAB: 'switchTab',
// 对象转换url参数
object2param: (obj) => {
if(!obj || Object.keys(obj).length <= 0){
return ""
}
let result = "?"
Object.keys(obj).forEach(k => {
let val = obj[k]
// H5需要转码 其他平台不需要
// #ifdef H5
val = encodeURIComponent(val)
// #endif
result += `${k}=${val}&`
})
return result.substr(0, (result.length - 1));
},
// uni.navigateTo函数的封装 保留当前页面跳转到应用内的某个页面使用uni.navigateBack可以返回到原页面。
// 参数: pagesIdOrUrl(路径或者pageId), 页面参数, 扩展参数
to: (pagesIdOrUrl, params = {}, type = model.GO_TYPE_TO, extObject = {}) => {
// 使用ID作为标识
if(pagesIdOrUrl.indexOf('PAGES_') == 0){
pagesIdOrUrl = ALL_PAGES[pagesIdOrUrl]
}
pagesIdOrUrl += model.object2param(params)
if(type == model.GO_TYPE_TO){
uni.navigateTo(Object.assign({ url: pagesIdOrUrl }, extObject))
}
if(type == model.GO_TYPE_REDIRECT){
uni.redirectTo(Object.assign({ url: pagesIdOrUrl }, extObject))
}
if(type == model.GO_TYPE_RELAUNCH){
uni.reLaunch(Object.assign({ url: pagesIdOrUrl }, extObject))
}
if(type == model.GO_TYPE_SWITCHTAB){
uni.switchTab(Object.assign({ url: pagesIdOrUrl }, extObject))
}
},
// 跳转到通用搜索页面
toSearchPage: (pageType, extObject = {}) => {
model.to("PAGES_LIST_SEARCH", Object.assign({type: pageType}, extObject))
},
// delta 返回到第几页, refEmitEventName: 触发全局更新函数 (更新 list and search )
back: (delta = 1, refEmitEventName) => {
if(refEmitEventName){
emit.refPageAndSearchEmit(refEmitEventName)
}
uni.navigateBack(delta)
}
}
export default model

62
commons/utils/infoBox.js Normal file
View File

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

View File

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

View File

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

View File

@@ -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 = '' //重置 数据
})
}
}

View File

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

View File

@@ -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张表。

1625
commons/utils/qrCode.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
export const objToArrary = (obj) => {
return Object.entries(obj).map(([key, value]) => ({
key,
...value,
}))
}

38
commons/utils/saveImg.js Normal file
View File

@@ -0,0 +1,38 @@
// 保存图片
export function saveHeadImgFile(base64, quality) {
const bitmap = new plus.nativeObj.Bitmap("test");
return new Promise((resolve, reject) => {
// 从本地加载Bitmap图片
bitmap.loadBase64Data(base64, function() {
const url = "_doc/" + getTimeStamps() + ".png"; // url为时间戳命名方式
bitmap.save(url, {
overwrite: true, // 是否覆盖
quality: quality // 图片清晰度
}, (i) => {
console.log(url)
uni.saveImageToPhotosAlbum({
filePath: url,
success: function() {
resolve({
code: 0,
msg: '保存成功',
filePath: url
});
},
fail:function(){
msg:'保存失败'
}
});
}, (e) => {
reject('保存图片失败:' + JSON.stringify(e));
});
}, (e) => {
reject('加载图片失败:' + JSON.stringify(e));
});
})
}
function getTimeStamps (){
return (new Date()).valueOf()
}

View File

@@ -0,0 +1,196 @@
/**
* 存储管理对象
* 目标:将现有系统的所有需要存储的数据,统一管理
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/04/13 07:18
*/
import appConfig from "@/config/appConfig.js"
// 应用级vue级别缓存 当存在时则读取此值, 否则读取storage中的值。 vue线程内的缓存不必要每次读取应用数据影响性能
const appCache = {
tokenVal: null, // token取值
currentUser: null, // 当前商户信息
}
const model = {
// 退出清空所有的缓存数据。 (不包含 环境相关)
cleanByLogout: () => {
// 1. 清空app级别缓存。
Object.keys(appCache).forEach(k => appCache[k] = null)
let envName = model.env() // 获取到当前的环境变量
uni.clearStorageSync() // 清除所有的缓存信息
model.env(envName) // 重置env
},
// 获取和放置token
token: (val, isDelete = false) => {
if (isDelete) {
appCache.tokenVal = ""
return uni.removeStorageSync(appConfig.tokenKey)
}
if (val) {
// 有值,为放置
appCache.tokenVal = val
uni.setStorageSync(appConfig.tokenKey, val)
} else {
// 否则为获取
if (!appCache.tokenVal) {
//缓存取不到,获取应用本地信息
appCache.tokenVal = uni.getStorageSync(appConfig.tokenKey)
}
return appCache.tokenVal
}
},
// 获取和放置shopId
shopId: (val, isDelete = false) => {
if (isDelete) {
appCache.shopId = ""
return uni.removeStorageSync('shopId')
}
if (val) {
// 有值,为放置
appCache.shopId = val
uni.setStorageSync('shopId', val)
} else {
// 否则为获取
if (!appCache.shopId) {
//缓存取不到,获取应用本地信息
appCache.shopId = uni.getStorageSync('shopId')
}
return appCache.shopId
}
},
// 已经登录的用户记录
loggedInUser: (addUserName = null, removeUserName = null) => {
let key = "loggedInUserList"
// 删除
if (removeUserName) {
let nameList = uni.getStorageSync(key) || []
if (nameList.length <= 0) {
//不存在数据
return false
}
let hasUserIndex = nameList.indexOf(removeUserName)
if (hasUserIndex >= 0) {
nameList.splice(hasUserIndex, 1) //删除
uni.setStorageSync(key, nameList)
}
return false
}
// 有新插入的记录
if (addUserName) {
let nameList = uni.getStorageSync(key) || []
let hasUser = false
for (let i = 0; i < nameList.length; i++) {
if (nameList[i] == addUserName) {
hasUser = true
}
}
// 包含记录
if (hasUser) {
return false
}
// 最多存储 5 个
if (nameList.length >= 5) {
nameList.splice(0, 1) //删除第一个
}
nameList.push(addUserName)
uni.setStorageSync(key, nameList)
//获取
} else {
return uni.getStorageSync(key) || [] //默认空数组
}
},
// 用户信息
userInfo: (currentUserInfo) => {
if (currentUserInfo) {
// 仅保存基础数据
let saveUser = {
sysUserId: currentUserInfo.sysUserId, // 用户ID
realname: currentUserInfo.realname, // 用户姓名
avatarUrl: currentUserInfo.avatarUrl, // 头像
telphone: currentUserInfo.telphone, // 手机号
userType: currentUserInfo.userType, // 用户类型
mchNo: currentUserInfo.userNo, // 商户No
mchShortName: currentUserInfo.shortName, // 商户简称
mchType: currentUserInfo.mchType, // 商户类型
mchLevel: currentUserInfo.mchLevel, // 商户级别
isHasMemberEnt:currentUserInfo.isHasMemberEnt,// 是否购买会员模块
entIdList: currentUserInfo.entIdList, // 权限集合List
}
uni.setStorageSync("currentUserInfo", saveUser) // 改变存储
appCache.currentUser = null
}
if(!appCache.currentUser){ // 获取缓存数据
appCache.currentUser = uni.getStorageSync("currentUserInfo")
}
return appCache.currentUser
},
// 项目环境变量:(测试、 生产的切换)
env: (envMode) => {
if (envMode) {
uni.setStorageSync(appConfig.storeEnvEnumKey, envMode) // 改变存储
}
return uni.getStorageSync(appConfig.storeEnvEnumKey)
},
// push 状态是否开启
pushIsOpen: (pushFlag) => {
if (pushFlag) {
uni.setStorageSync('pushFlag', pushFlag) // 改变存储
}
return uni.getStorageSync('pushFlag')
},
// 网站信息
siteInfos: (siteInfos) => {
if (siteInfos) {
uni.setStorageSync("siteInfos", siteInfos) // 改变存储
}
return uni.getStorageSync("siteInfos")
},
// unipush2 cid
uniPush2Cid: (uniPush2Cid) => {
if (uniPush2Cid) {
uni.setStorageSync("uniPush2Cid", uniPush2Cid) // 改变存储
}
return uni.getStorageSync("uniPush2Cid")
},
uploadImgSize: (uploadImgSize) => {
if (uploadImgSize) {
uni.setStorageSync("uploadImgSize", uploadImgSize) // 存储 上传 图片大小限制
}
return uni.getStorageSync("uploadImgSize")
},
}
export default model

View File

@@ -0,0 +1,14 @@
import dayjs from 'dayjs' //时间格式库
import infoBox from '@/commons/utils/infoBox.js'
// 时间校验 用于筛选 开始 时间不能大于结束 开始结束时间必选 时间 返回值 true 和 false
export const startAndEndTime = (start, end) => {
if (!start || !end) {
infoBox.showToast('请选择开始或结束时间')
return false
}
if (dayjs(start).isAfter(end)) {
infoBox.showToast('开始时间不能大于结束时间')
return false
}
return true
}

54
commons/utils/timer.js Normal file
View File

@@ -0,0 +1,54 @@
/**
* 任务执行器
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/15 16:30
*/
const model = {
// 任务启动工具, 每 xxs调用一次 知道多次x次为止。
// 注意: 启动后将立马调用一次, 而不是1s后再调用。
// 参数:
// allCount: 全部的次数 支持promise 并不一定是 秒)
// stepSecond 步伐(单位: 秒)
// callbackFunc 回调函数, 支持返回 boolean 或者 promise ,
// 注意: boolean类型 true 进入下一次循环, false: 停止任务。
// promise类型 then 进入下一次循环, catch 停止任务。
startTimeoutTask: (stepSecond, allCount, callbackFunc) => {
// 不存在回调函数
if(!callbackFunc){
return false;
}
let callbackResult = callbackFunc(allCount)
// 明确返回false, 说明不再循环
if(callbackResult === false){
return false
}
// 不包含剩余次数了。
if(allCount <= 0){
return false
}
// promise
if(typeof callbackResult == 'object'){
callbackResult.then(() => {
setTimeout(() => model.startTimeoutTask(stepSecond, --allCount, callbackFunc), (stepSecond * 1000) )
})
}else{ // 其他boolean类型 或返回不明确, 继续下一次任务。
setTimeout(() => model.startTimeoutTask(stepSecond, --allCount, callbackFunc), (stepSecond * 1000) )
}
}
}
export default model

View File

@@ -0,0 +1,62 @@
/**
* 统一扫码, 支持登录、 码牌绑定、 打印机、 等
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/22 10:38
*/
import { $parseQrCodeUrl } from '@/http/apiManager.js'
const model = {
// 扫码结果类型
QR_TYPE_LOGIN: 'QR_TYPE_LOGIN', // 登录
QR_TYPE_QRC: 'QR_TYPE_QRC', // 码牌
QR_TYPE_PRINTER: 'QR_TYPE_PRINTER', // 打印机
QR_TYPE_OTHER: 'QR_TYPE_OTHER', // 其他
returnFunc: (type, bizValue, originQrVal) => {
return { type: type, bizValue: bizValue, originQrVal: originQrVal}
},
// 解析 码牌
parseQrc: (originQrVal) => {
return $parseQrCodeUrl(originQrVal).then( ({bizData}) => {
return model.returnFunc(model.QR_TYPE_QRC, bizData, originQrVal)
})
},
// 返回 类型 和 扫码的值
// 参数: 是否解析qrc , 默认不解析
scan: (isParseQRC = false) => {
return uni.scanCode().then(({ result }) => {
// 登录类型
if(result.startsWith("JEEPAY_LOGIN_QR_")){
return model.returnFunc(model.QR_TYPE_LOGIN, result.substring(16), result)
}
if(isParseQRC){
return model.parseQrc(result).then( (res) => {
return res;
}).catch(() => {
return model.returnFunc(model.QR_TYPE_OTHER, result, result)
})
}else{
return model.returnFunc(model.QR_TYPE_OTHER, result, result)
}
})
}
}
export default model

View File

@@ -0,0 +1,14 @@
export default {
get(key) {
return uni.getStorageSync(key)
},
set(key, value) {
uni.setStorageSync(key, value)
},
del(key) {
uni.removeStorageSync(key)
},
clear() {
uni.clearStorageSync()
}
}

View File

@@ -0,0 +1,121 @@
import { $versionDetection } from '@/http/apiManager.js';
import appConfig from '@/config/appConfig.js'
// app更新
function appPlusUpdate(sign){
// 获取版本号
plus.runtime.getProperty(plus.runtime.appid, function(inf) {
// 调起接口查询
$versionDetection({versionNumber: inf.versionCode})
.then(({ bizData }) => {
//返回data为空或者版本号一致
if (!bizData || Object.keys(bizData).length == 0 || !bizData.versionSerialNumber || bizData.versionSerialNumber == inf.versionCode) {
if(sign === 'checked') {
uni.showToast({
title: '已是最新版本'
})
}
return false;
}
// 是否强制更新
let isForceUpdate = bizData.forceUpdate == 1
uni.showModal({
title: '发现新版本:' + bizData.versionName,
showCancel: !isForceUpdate ,
content: bizData.versionDesc,
confirmText: '立即更新',
confirmColor: '#108EE9',
success: function(r) {
if (r.confirm) {
downLoad(bizData.downloadUrl);
}else{
// 强制更新也需要更新
if(isForceUpdate){
downLoad(bizData.downloadUrl);
}
}
}
});
});
});
}
//下载更新包
function downLoad(url) {
if (!url) {
uni.showToast({icon: 'none',title: '下载地址错误'});
return false;
}
// 下载文件
uni.showLoading({title: '更新中'});
uni.downloadFile({
url: url,
success: res => {
uni.hideLoading();
if (res.statusCode === 200) {
uni.showToast({title: '下载成功'});
plus.runtime.install(res.tempFilePath);
}
},
fail: res => {
uni.hideLoading();
}
});
}
// 获取当前版本 & 检查
export function getCurrentVersionPromise() {
let isApp = false
// #ifdef APP-PLUS
isApp = true
// #endif
if(!isApp){
return Promise.reject()
}
// 获取版本号
return new Promise((resolve, reject) => {
plus.runtime.getProperty(plus.runtime.appid, function(inf) {
resolve(inf)
})
})
}
// 获取当前版本 & 检查
export function checkCurrVersion(sign) {
// #ifdef APP-PLUS
switch(uni.getSystemInfoSync().platform){
case 'android':
appPlusUpdate(sign) //仅安卓更新
break;
case 'ios':
break;
default:
break;
}
// #endif
}
//同步取出ext.json对象
export function getExtStoreId(){
try{
const extConfig = uni.getExtConfigSync()
if(extConfig.domain){
appConfig.env.JEEPAY_BASE_URL = extConfig.domain
}
// uni.showToast({title: JSON.stringify(extConfig),icon:"none",duration:3000});
console.log(extConfig,'extJson对象');
return extConfig;
}catch(err){
console.log(err,'getExtStoreId__error')
}
}

1
commons/week.js Normal file
View File

@@ -0,0 +1 @@
export const $weeks=['周一','周二','周三','周四','周五','周六','周日'];