代码更新

This commit is contained in:
GaoHao 2025-02-26 19:46:20 +08:00
parent 7519ffced3
commit b4a0393d2d
413 changed files with 7483 additions and 60762 deletions

11
App.vue
View File

@ -3,10 +3,15 @@
App.vue本身不是页面这里不能编写视图元素也就是没有<template>
-->
<script setup>
import {
onLaunch
} from '@dcloudio/uni-app';
import { onLaunch } from '@dcloudio/uni-app';
import { getFindBySource } from '@/http/yskApi/version.js'
import appConfig from '@/config/appConfig.js';
import { provide } from 'vue';
import WebsocketUtil from '@/commons/utils/websocket.js'
const websocketUtil = new WebsocketUtil(appConfig.wss, 5000); // WebSocket
provide('websocketUtil', websocketUtil); //
onLaunch(() => {
let that = this
uni.hideTabBar()

View File

@ -1,27 +0,0 @@
{
"version" : "1",
"prompt" : "template",
"title" : "服务协议和隐私政策",
"message" : "  请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>  你可阅读<a href=\"static/service.html\">《服务协议》</a>和<a href=\"static/privacy.html\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"second" : {
"title" : "确认提示",
"message" : "  进入应用前,你需先同意<a href=\"static/service.html\">《服务协议》</a>和<a href=\"static/privacy.html\">《隐私政策》</a>,否则将退出应用。",
"buttonAccept" : "同意并继续",
"buttonRefuse" : "退出应用"
},
"styles" : {
"backgroundColor" : "#FFFFFF",
"borderRadius" : "5px",
"title" : {
"color" : "#262626"
},
"buttonAccept" : {
"color" : "#3981FF"
},
"buttonRefuse" : {
"color" : "#A6A6A6"
}
}
}

16
api/area.js Normal file
View File

@ -0,0 +1,16 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取区域列表
* @returns
*/
export function getShopArea(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopArea`,
method: "GET",
data: {
...data
}
})
}

86
api/callTable.js Normal file
View File

@ -0,0 +1,86 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取叫号队列
* @returns
*/
export function getCallTableQueue(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable/queue`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取叫号记录列表
* @returns
*/
export function getCallRecord(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable/callRecord`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取叫号桌型
* @returns
*/
export function getCallTable(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取叫号号码
* @returns
*/
export function callTableTakeNumber(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable/takeNumber`,
method: "POST",
data: {
...data
}
})
}
/**
* 执行叫号
* @returns
*/
export function callTableCall(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable/call`,
method: "POST",
data: {
...data
}
})
}
/**
* 修改叫号状态
* @returns
*/
export function updateCallTableState(data, urlType = 'account') {
return request({
url: `${urlType}/admin/callTable/updateState`,
method: "PUT",
data: {
...data
}
})
}

55
api/cateGory.js Normal file
View File

@ -0,0 +1,55 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取分类分页
* @returns
*/
export function categoryPage(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category/page`,
method: "GET",
data: {
...data
}
})
}
/**
* 分类添加
* @returns
*/
export function addCategory(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category`,
method: "POST",
data: {
...data
}
})
}
/**
* 分类修改
* @returns
*/
export function putCategory(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category`,
method: "PUT",
data: {
...data
}
})
}
/**
* 分类删除
* @returns
*/
export function delCategory(id, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category/${id}`,
method: "DELETE",
})
}

180
api/cons.js Normal file
View File

@ -0,0 +1,180 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取耗材分页
* @returns
*/
export function getConsPage(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons/page`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取耗材列表
* @returns
*/
export function getConsList(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons/list`,
method: "GET",
data: {
...data
}
})
}
/**
* 耗材添加
* @returns
*/
export function addCons(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons`,
method: "POST",
data: {
...data
}
})
}
/**
* 耗材修改
* @returns
*/
export function editCons(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons`,
method: "PUT",
data: {
...data
}
})
}
/**
* 获取耗材类别
* @returns
*/
export function getConsGrpupPage(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group/page`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取耗材类别
* @returns
*/
export function getConsGrpupList(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group/list`,
method: "GET",
data: {
...data
}
})
}
/**
* 新增耗材类别
* @returns
*/
export function addConsGrpup(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group`,
method: "POST",
data: {
...data
}
})
}
/**
* 修改耗材类别
* @returns
*/
export function editConsGrpup(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group`,
method: "PUT",
data: {
...data
}
})
}
/**
* 启用耗材类别
* @returns
*/
export function consGrpupEnable(id, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group/enable/${id}`,
method: "POST",
})
}
/**
* 禁用耗材类别
* @returns
*/
export function consGrpupDisable(id, urlType = 'product') {
return request({
url: `${urlType}/admin/product/cons-group/disable/${id}`,
method: "POST",
})
}
/**
* 耗材入库
* @returns
*/
export function consStockIn(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/stock/in`,
method: "POST",
data: {
...data
}
})
}
/**
* 耗材出库
* @returns
*/
export function stockOut(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/stock/out`,
method: "POST",
data: {
...data
}
})
}
/**
* 库存盘点
* @returns
*/
export function stockCheck(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/stock/check`,
method: "POST",
data: {
...data
}
})
}

44
api/coupon.js Normal file
View File

@ -0,0 +1,44 @@
import http from '@/http/http.js'
const request = http.request
/**
* 店铺优惠券列表
* @returns
*/
export function getCouponList(data, urlType = 'account') {
return request({
url: `${urlType}/admin/coupon`,
method: "GET",
data: {
...data
}
})
}
/**
* 店铺优惠券新增
* @returns
*/
export function addCoupon(data, urlType = 'account') {
return request({
url: `${urlType}/admin/coupon`,
method: "POST",
data: {
...data
}
})
}
/**
* 店铺优惠券修改
* @returns
*/
export function updateCoupon(data, urlType = 'account') {
return request({
url: `${urlType}/admin/coupon`,
method: "PUT",
data: {
...data
}
})
}

30
api/freeDing.js Normal file
View File

@ -0,0 +1,30 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取当前店铺霸王餐配置信息列表
* @returns
*/
export function getFreeDing(data, urlType = 'account') {
return request({
url: `${urlType}/admin/freeDing`,
method: "GET",
data: {
...data
}
})
}
/**
* 修改霸王餐配置信息
* @returns
*/
export function updateFreeDing(data, urlType = 'account') {
return request({
url: `${urlType}/admin/freeDing`,
method: "PUT",
data: {
...data
}
})
}

24
api/index.js Normal file
View File

@ -0,0 +1,24 @@
import http from '@/http/http.js'
const request = http.request
/**
* 文件上传
* @returns
*/
export function uploadFile(file, data, urlType = 'account') {
return http.upload(`${urlType}/admin/common/upload`,data,file)
}
/**
* 获取店铺权限列表
* @returns
*/
export function getShopPermission(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopPermission`,
method: "GET",
data: {
...data
}
})
}

30
api/login.js Normal file
View File

@ -0,0 +1,30 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取验证码
* @returns
*/
export function authCaptcha(data, urlType = 'account') {
return request({
url: `${urlType}/admin/auth/captcha`,
method: "GET",
data: {
...data
}
})
}
/**
* 登录
* @returns
*/
export function login(data, urlType = 'account') {
return request({
url: `${urlType}/admin/auth/login`,
method: "POST",
data: {
...data
}
})
}

45
api/order.js Normal file
View File

@ -0,0 +1,45 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取订单列表
* @returns
*/
export function getOrderList(data, urlType = 'order') {
return request({
url: `${urlType}/admin/order`,
method: "POST",
data: {
...data
}
})
}
/**
* 历史订单(多次下单使用)
* @returns
*/
export function getHistoryOrder(data, urlType = 'order') {
return request({
url: `${urlType}/admin/order/historyOrder`,
method: "GET",
data: {
...data
}
})
}
/**
* 生成订单
* @returns
*/
export function createOrder(data, urlType = 'order') {
return request({
url: `${urlType}/admin/order/createOrder`,
method: "POST",
data: {
...data
}
})
}

16
api/payType.js Normal file
View File

@ -0,0 +1,16 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取支付方式列表
* @returns
*/
export function getPayTypeList(data, urlType = 'account') {
return request({
url: `${urlType}/admin/payType`,
method: "GET",
data: {
...data
}
})
}

69
api/printer.js Normal file
View File

@ -0,0 +1,69 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取打印机列表
* @returns
*/
export function getPrinter(data, urlType = 'account') {
return request({
url: `${urlType}/admin/printer`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取打印机详情
* @returns
*/
export function getPrinterDetail(data, urlType = 'account') {
return request({
url: `${urlType}/admin/printer/detail`,
method: "GET",
data: {
...data
}
})
}
/**
* 添加打印机
* @returns
*/
export function addPrinter(data, urlType = 'account') {
return request({
url: `${urlType}/admin/printer`,
method: "POST",
data: {
...data
}
})
}
/**
* 修改打印机
* @returns
*/
export function updatePrinter(data, urlType = 'account') {
return request({
url: `${urlType}/admin/printer`,
method: "PUT",
data: {
...data
}
})
}
/**
* 删除打印机
* @returns
*/
export function delPrinter(id, urlType = 'account') {
return request({
url: `${urlType}/admin/product/vendor/${id}`,
method: "DELETE",
})
}

259
api/product.js Normal file
View File

@ -0,0 +1,259 @@
import http from '@/http/http.js'
const request = http.request
// 商品----------------------------------------------------------------------------------------------------
/**
* 获取商品列表
* @returns
*/
export function getProductList(data, urlType = 'product' ,showLoading) {
return request({
url: `${urlType}/admin/product/page`,
method: "GET",
data: {
...data
},
showLoading
})
}
/**
* 获取商品详情
* @returns
*/
export function getProductDetail (id, urlType = 'product') {
return request({
url: `${urlType}/admin/product/${id}`,
method: "GET",
})
}
/**
* 添加商品
* @returns
*/
export function addProduct(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product`,
method: "POST",
data: {
...data
}
})
}
/**
* 删除商品
* @returns
*/
export function delProduct(id, urlType = 'product') {
return request({
url: `${urlType}/admin/product/${id}`,
method: "DELETE",
})
}
/**
* 商品上下架
* @returns
*/
export function productOnOff (data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/on-off`,
method: "POST",
data: {
...data
}
})
}
/**
* 商品售罄
* @returns
*/
export function productMarkIsSoldOut (data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/markIsSoldOut`,
method: "POST",
data: {
...data
}
})
}
/**
* 修改商品
* @returns
*/
export function updateProduct(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product`,
method: "PUT",
data: {
...data
}
})
}
/**
* 绑定耗材
* @returns
*/
export function productBind(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/bind`,
method: "POST",
data: {
...data
}
})
}
// 商品分类----------------------------------------------------------------------------------------------------
/**
* 获取商品分类列表
* @returns
*/
export function getCategoryList(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/category/list`,
method: "GET",
data: {
...data
}
})
}
// 商品单位----------------------------------------------------------------------------------------------------
/**
* 获取商品单位列表
* @returns
*/
export function getProdUnitList(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/unit/list`,
method: "GET",
data: {
...data
}
})
}
// 商品规格----------------------------------------------------------------------------------------------------
/**
* 获取商品规格列表
* @returns
*/
export function getSpecList(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/spec/list`,
method: "GET",
data: {
...data
}
})
}
/**
* 添加商品规格
* @returns
*/
export function addSpec(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/spec`,
method: "POST",
data: {
...data
}
})
}
/**
* 修改商品规格
* @returns
*/
export function updateSpec(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/spec`,
method: "PUT",
data: {
...data
}
})
}
/**
* 删除商品规格
* @returns
*/
export function delSpec(id, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/spec/${id}`,
method: "DELETE",
})
}
// 商品分组----------------------------------------------------------------------------------------------------
/**
* 获取商品分组列表
* @returns
*/
export function getProdGroupPage(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/group/page`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取商品分组详情
* @returns
*/
export function getProdGroupDetail(id, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/group/${id}`,
method: "GET",
})
}
/**
* 商品分组添加
* @returns
*/
export function addProdGroup(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/group`,
method: "POST",
data: {
...data
}
})
}
/**
* 商品分组修改
* @returns
*/
export function updateProdGroup(data, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/group`,
method: "PUT",
data: {
...data
}
})
}
/**
* 商品分组删除
* @returns
*/
export function delProdGroup(id, urlType = 'product') {
return request({
url: `${urlType}/admin/prod/group/${id}`,
method: "DELETE",
})
}

16
api/role.js Normal file
View File

@ -0,0 +1,16 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取角色列表
* @returns
*/
export function getRoleList(data, urlType = 'account') {
return request({
url: `${urlType}/admin/role/list`,
method: "GET",
data: {
...data
}
})
}

30
api/shop.js Normal file
View File

@ -0,0 +1,30 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取店铺详情
* @returns
*/
export function getShopInfo(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopInfo/detail`,
method: "GET",
data: {
...data
}
})
}
/**
* 修改店铺详情
* @returns
*/
export function editShopInfo(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopInfo`,
method: "PUT",
data: {
...data
}
})
}

72
api/shopUser.js Normal file
View File

@ -0,0 +1,72 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取店铺用户概述信息
* @returns
*/
export function shopUserSummary(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopUser/summary`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取店铺用户列表
* @returns
*/
export function shopUserList(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopUser`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取店铺用户新增
* @returns
*/
export function shopUserAdd(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopUser`,
method: "POST",
data: {
...data
}
})
}
/**
* 店铺用户修改
* @returns
*/
export function shopUserPut(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopUser`,
method: "PUT",
data: {
...data
}
})
}
/**
* 店铺用户余额修改
* @returns
*/
export function shopUserMoney(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopUser/money`,
method: "PUT",
data: {
...data
}
})
}

86
api/staff.js Normal file
View File

@ -0,0 +1,86 @@
import http from '@/http/http.js'
const request = http.request
/**
* 员工列表
* @returns
*/
export function shopStaffList(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取员工对应的权限idid
* @returns
*/
export function getShopStaffPermission(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff/permission`,
method: "GET",
data: {
...data
}
})
}
/**
* 员工详情
* @returns
*/
export function shopStaffDetail(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff/detail`,
method: "GET",
data: {
...data
}
})
}
/**
* 员工添加
* @returns
*/
export function shopStaffAdd(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff`,
method: "POST",
data: {
...data
}
})
}
/**
* 员工修改
* @returns
*/
export function shopStaffPut(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff`,
method: "PUT",
data: {
...data
}
})
}
/**
* 员工删除
* @returns
*/
export function shopStaffDel(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopStaff`,
method: "DELETE",
data: {
...data
}
})
}

44
api/table.js Normal file
View File

@ -0,0 +1,44 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取台桌列表
* @returns
*/
export function getShopTable(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopTable`,
method: "GET",
data: {
...data
}
})
}
/**
* 获取台桌详情
* @returns
*/
export function getShopTableDetail(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopTable/detail`,
method: "GET",
data: {
...data
}
})
}
/**
* 台桌绑定
* @returns
*/
export function shopTableBind(data, urlType = 'account') {
return request({
url: `${urlType}/admin/shopTable/bind`,
method: "GET",
data: {
...data
}
})
}

56
api/vendor.js Normal file
View File

@ -0,0 +1,56 @@
import http from '@/http/http.js'
const request = http.request
/**
* 获取供应商列表
* @returns
*/
export function getVendorPage(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/vendor/page`,
method: "GET",
data: {
...data
}
})
}
/**
* 添加供应商
* @returns
*/
export function addVendor(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/vendor`,
method: "POST",
data: {
...data
}
})
}
/**
* 编辑供应商
* @returns
*/
export function editVendor(data, urlType = 'product') {
return request({
url: `${urlType}/admin/product/vendor`,
method: "PUT",
data: {
...data
}
})
}
/**
* 删除供应商
* @returns
*/
export function delVendor(id, urlType = 'product') {
return request({
url: `${urlType}/admin/product/vendor/${id}`,
method: "DELETE",
})
}

View File

@ -28,13 +28,11 @@ export const $types = [{
// 商品默认sku
export const $defaultSku = {
originPrice: '',
costPrice: '',
salePrice: '',
memberPrice: '',
costPrice: '',
originPrice: '',
// stockNumber: '',
firstShared: '',
suit: 1,
suitNum: '',
barCode: `${uni.getStorageSync("shopId")}${dayjs().valueOf()}`,
}

View File

@ -5,17 +5,17 @@ export default {
label: '待支付'
},
{
key: 'unsend',
label: '待发货'
key: 'in-production',
label: '制作中'
},
{
key: 'closed',
key: 'wait-out',
label: '待取餐'
},
{
key: 'done',
label: '订单完成'
},
{
key: 'send',
label: '已发'
},
{
key: 'refunding',
label: '申请退单'
@ -24,26 +24,30 @@ export default {
key: 'refund',
label: '退单'
},
{
key: 'part-refund',
label: '部分退单'
},
{
key: 'cancelled',
label: '取消订单'
},
{
key: 'merge',
label: '合台'
},
{
key: 'pending',
label: '挂单'
},
{
key: 'activate',
label: '激活'
},
{
key: 'paying',
label: '支付中'
}
// {
// key: 'merge',
// label: '合台'
// },
// {
// key: 'pending',
// label: '挂单'
// },
// {
// key: 'activate',
// label: '激活'
// },
// {
// key: 'paying',
// label: '支付中'
// }
],
sendType: [
{

View File

@ -1,36 +1,33 @@
export const $status = {
pending: {
label: "挂单中",
type: "#E6A23C",
},
using: {
idle: {
label: "空闲",
type: "#3F9EFF",
},
using: {
label: "使用中",
type: "#fa5555",
},
subscribe: {
label: "预定",
type: "rgb(34, 191, 100)",
},
closed: {
label: "关台",
type: "rgb(221,221,221)",
},
opening: {
label: "开台中",
type: "#fa5555",
},
paying: {
label: "结算中",
type: "#E6A23C",
},
idle: {
label: "空闲",
type: "#3F9EFF",
},
subscribe: {
label: "预定",
type: "rgb(34, 191, 100)",
},
closed: {
label: "关台",
type: "rgb(221,221,221)",
},
// opening: {
// label: "开台中",
// type: "#67C23A",
// },
cleaning: {
label: "待清台",
type: "#FAAD14",
},
cleaning: {
label: "待清台",
type: "#FAAD14",
},
// paying: {
// label: "结算中",
// type: "#E6A23C",
// },
unbind: {
label: "未绑定",
type: "rgb(221,221,221)",

View File

@ -17,7 +17,7 @@ export function canTuicai(orderInfo, item) {
return orderInfo.status == 'unpaid' && orderInfo.useType != 'dine-in-before' && item.status != 'return'
}
export function canTuiKuan(orderInfo, item) {
return orderInfo.status == 'closed' && item.status != 'return' && item.status != 'refund' && item.status !=
return orderInfo.status == 'done' && item.status != 'return' && item.status != 'refund' && item.status !=
'refunding'
}
export function isTuiCai(item) {

View File

@ -1,6 +1,4 @@
import {
$hasPermission
} from '@/http/yskApi/shop.js'
import { $hasPermission } from '@/http/yskApi/shop.js'
import infoBox from '@/commons/utils/infoBox.js'
const $PermissionObj = {
@ -147,17 +145,18 @@ export async function hasPermission(params) {
if (!params) {
return infoBox.showToast('未找到相关权限请检查代码或在权限配置文件commons/utils/hasPermission.js文件进行修改或增加')
}
const option = Object.assign({
tips: true,
key: '',
text: ''
}, params)
const res = await $hasPermission({
code: params.key
})
if (!res && option.tips) {
infoBox.showToast('您没有' + params.text + '权限!')
}
return res
// const option = Object.assign({
// tips: true,
// key: '',
// text: ''
// }, params)
// const res = await $hasPermission({
// code: params.key
// })
// if (!res && option.tips) {
// infoBox.showToast('您没有' + params.text + '权限!')
// }
// return res
return true
}

View File

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

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

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

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

@ -1,10 +0,0 @@
创建 云空间 上传云函数 云函数 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张表。

View File

@ -18,15 +18,10 @@ const appCache = {
const model = {
setLogin(res){
const user=res.user.user
uni.setStorageSync('logoutHandle',false)
uni.setStorageSync('shopId', res.shopId)
uni.setStorageSync('shopName',res.shopName)
uni.setStorageSync('logo',res.logo)
uni.setStorageSync('shopInfo',res.shopInfo)
uni.setStorageSync('loginType',res.loginType)
uni.setStorageSync('shopUserId',user.id)
if(res.loginType=='staff'){
uni.setStorageSync('merchantName',user.createBy||user.updateBy)
if(res.loginType=='1'){
// uni.setStorageSync('merchantName',user.createBy||user.updateBy)
}
},
// 退出清空所有的缓存数据。 (不包含 环境相关)
@ -51,14 +46,14 @@ const model = {
if (val) {
// 有值,为放置
appCache.tokenVal = val
appCache.tokenVal = val.tokenValue
uni.setStorageSync(appConfig.tokenKey, val)
} else {
// 否则为获取
if (!appCache.tokenVal) {
//缓存取不到,获取应用本地信息
appCache.tokenVal = uni.getStorageSync(appConfig.tokenKey)
appCache.tokenVal = uni.getStorageSync(appConfig.tokenKey).tokenValue
}
return appCache.tokenVal
}
@ -254,6 +249,8 @@ const model = {
if (envMode) {
uni.setStorageSync(appConfig.storeEnvEnumKey, envMode) // 改变存储
}
console.log(appConfig.storeEnvEnumKey)
return uni.getStorageSync(appConfig.storeEnvEnumKey)
},

140
commons/utils/websocket.js Normal file
View File

@ -0,0 +1,140 @@
import { reactive, ref } from 'vue';
// WebSocket 工具类,封装了 WebSocket 的连接、发送、接收、心跳、重连和关闭等操作
class WebsocketUtil {
// 构造函数,初始化 WebSocket 连接
constructor(url, time, params) {
this.url = url; // WebSocket 服务器的 URL
this.params = params; // WebSocket 服务器的 URL
this.time = time; // 心跳发送的间隔时间(秒)
this.socketTask = null; // WebSocket 任务对象
this.isOpen = false; // WebSocket 连接是否打开
this.reconnectTimeout = null; // 重连定时器
this.heartbeatInterval = null; // 心跳定时器
this.messageCallbacks = []; // 存储外部注册的消息回调函数的数组
// 初始化 WebSocket 连接
this.initializeWebSocket();
}
// 初始化 WebSocket 连接
initializeWebSocket() {
this.socketTask = uni.connectSocket({
url: this.url,
success: () => {
console.log('WebSocket连接成功');
return this.socketTask;
},
fail: (error) => {
console.error('WebSocket连接失败', error);
this.reconnect();
}
});
this.socketTask.onOpen((res) => {
console.log('WebSocket连接正常==',res);
this.isOpen = true;
// 连接成功后启动心跳和消息监听
this.startHeartbeat();
this.listenForMessages();
// 注意:这里的 onClose 监听器应该放在 uni.connectSocket 调用之后
this.socketTask.onClose((result) => {
this.isOpen = false;
// if( this.isOpen ){
this.reconnect();
// }
});
});
}
// 启动心跳检测
startHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
}
this.heartbeatInterval = setInterval(() => {
if (this.isOpen) {
this.send('心跳检测','heartbeat');
}
}, this.time);
}
// 发送消息
send(data,type) {
if (this.socketTask && this.isOpen) {
this.socketTask.send({
data: data,
type: type||'heartbeat',
success: (res) => {
// console.log('消息发送成功', res);
},
fail: (error) => {
console.error('消息发送失败', error);
this.reconnect(); // 这里可能需要根据实际情况判断是否重连
}
});
}
}
// 监听 WebSocket 消息
listenForMessages() {
if (this.socketTask) {
this.socketTask.onMessage((res) => {
const { data } = res;
this.messageCallbacks.forEach(callback => callback(data.toString())); // 假设 data 是字符串或可转换为字符串
});
} else {
console.error('WebSocket 连接尚未建立,无法监听消息');
}
}
// 重连 WebSocket
reconnect() {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
this.reconnectTimeout = setTimeout(() => {
this.initializeWebSocket();
}, 3000);
}
// 关闭 WebSocket 连接
closeSocket() {
if (this.socketTask) {
uni.closeSocket({
success: () => {
console.log('WebSocket连接已关闭');
this.isOpen = false;
},
fail: (error) => {
console.error('关闭WebSocket连接失败', error);
}
});
this.socketTask = null;
}
}
// 外部注册消息回调函数
onMessage(callback) {
this.messageCallbacks.push(callback);
}
// 外部注销消息回调函数
offMessage(callback) {
this.messageCallbacks = this.messageCallbacks.filter(cb => cb !== callback);
}
// 销毁 WebSocket 连接,清理资源
destroy() {
this.closeSocket();
clearInterval(this.heartbeatInterval);
clearTimeout(this.reconnectTimeout);
this.messageCallbacks = [];
}
}
export default WebsocketUtil;

View File

@ -1,133 +0,0 @@
<template>
<uni-popup ref="refPopup" type="center" @change='change' :safe-area="false">
<view class="popup-wrapper">
<view class="title">用户服务协议与隐私政策</view>
<view class="content">
如需登录请先认真阅读并同意{{ $appName }}
<text class="info" @tap="go.to(service)">用户服务协议</text>
<text class="info" @tap="toPrivacy">隐私政策</text>
</view>
<view class="but-wrapper">
<view class="but-item" hover-class="touch-button" @tap="disagreeClose">拒绝</view>
<button class="but-item agree" id="agree-btn" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handAgree">同意</button>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import go from '@/commons/utils/go.js'
const props = defineProps({
service: { type: String },
privacy: { type: String }
})
const refPopup = ref(null)
const emits = defineEmits(['agree'])
const open = () => {
getPrivacy()
refPopup.value.open()
}
const vdata = reactive({})
const close = () => refPopup.value.close()
const toPrivacy = () => {
// #ifdef APP-PLUS
if (props.privacy) return go.to(props.privacy)
// #endif
//
// #ifdef MP-WEIXIN
wx.openPrivacyContract(
{
fail: () => {
uni.showToast({
title: '打开失败请稍后重试', //
icon: 'none'
})
},
}
)
// #endif
}
function disagreeClose () {
close()
}
//
const getPrivacy = () => {
wx.getPrivacySetting({
success: (r) => {
Object.assign(vdata, r)
if (vdata.needAuthorization) {
wx.onNeedPrivacyAuthorization(res => {
vdata.resolve = res
})
}
}
})
}
const handAgree = () => {
if (vdata.needAuthorization) {
vdata.resolve({ buttonId: 'agree-btn', event: 'agree' })
}
emits('agree')
close()
}
defineExpose({ open, close })
</script>
<style lang="scss" scoped>
.popup-wrapper {
width: 600rpx;
border-radius: 20rpx;
background: #FFF;
overflow: hidden;
.title {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx 0 50rpx;
text-align: center;
color: rgba(0, 0, 0, 0.50);
font-size: 28rpx;
}
.content {
padding-bottom: 70rpx;
margin: 0 auto;
width: 500rpx;
color: #000;
font-size: 28rpx;
line-height: 1.5;
.info {
color: $v-color-t21;
}
}
.but-wrapper {
display: flex;
.but-item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
height: 110rpx;
color: rgba(0, 0, 0, 0.70);
font-size: 32rpx;
font-weight: 400;
border-radius: 0;
}
.agree {
background: $jeepay-bg-primary;
color: #fff;
padding: 0;
}
}
}
</style>

View File

@ -1,185 +0,0 @@
<template>
<!-- 修改应用弹窗 -->
<uni-popup ref="popup" type="bottom" mask-background-color="rgba(0,0,0,.5)" :safe-area="false" @maskClick="emits('cancel')">
<view class="card-wrapper">
<view class="input-search">
<uni-easyinput
v-model="vadta.searchInfo"
prefixIcon="search"
:inputBorder="false"
:clearable="false"
:styles="styles"
type="text"
placeholder="搜索门店名称、ID"
placeholderStyle=" color: rgba(0,0,0,0.85);font-size: 30rpx;"
/>
<view class="search-button">搜索</view>
</view>
<!-- 循环开始部分 -->
<view class="store">
<view class="left">
<view class="store-dot"></view>
<view class="app-info">
<view class="app-name">应用名称</view>
<view class="app-code">62a55637e4b07ea5b8717ca3</view>
</view>
</view>
</view>
<!-- 循环结束部分 -->
<view class="footer-wrapper">
<view class="footer-main">
<view class="tips" v-if="tips">{{ tips }}</view>
<view class="footer-button">
<view class="flex-center" hover-class="touch-button" @tap="close">取消</view>
<view class="confirm flex-center" hover-class="touch-button">确认</view>
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
const emits = defineEmits(['cancel', 'confirm'])
const props = defineProps({
isAll: { type: Boolean, default: false }, // false
tips: { type: String }, //
})
const styles = reactive({
backgroundColor: '#f7f7f7',
height: '90rpx',
borderRadius: '10rpx',
color: '#000',
})
const vadta = reactive({
searchInfo: '',
})
const popup = ref(null)
const open = (val) => {
popup.value.open()
}
const close = () => {
emits('cancel')
popup.value.close()
}
const confirm = () => {}
onMounted(() => {
open()
})
defineExpose({ open })
</script>
<style lang="scss" scoped>
.card-wrapper {
border-radius: 32rpx 32rpx 0 0;
background-color: #fff;
overflow: hidden;
min-height: 70vh;
.input-search {
display: flex;
align-items: center;
padding-left: 10rpx;
margin: 30rpx;
border-radius: 10rpx;
background-color: #f7f7f7;
.search-button {
padding: 24rpx 30rpx;
font-size: 32rpx;
font-weight: 500;
color: #2980fd;
}
}
.store {
position: relative;
display: flex;
align-items: center;
padding: 0 40rpx;
height: 170rpx;
font-size: 30rpx;
.left {
display: flex;
align-items: center;
.store-dot {
align-self: start;
position: relative;
top: 2rpx;
margin-right: 20rpx;
width: 36rpx;
height: 36rpx;
background-color: #d7d8d9;
border-radius: 50%;
&::after {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
}
}
.active-dot {
background-color: #2980fd;
}
}
.app-info {
.app-code {
margin-top: 15rpx;
font-size: 26rpx;
color: #999;
}
}
}
.all-store::after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 40rpx;
right: 40rpx;
height: 1rpx;
background-color: #ededed;
}
.footer-wrapper {
height: 186rpx;
.footer-main {
position: fixed;
left: 0;
right: 0;
bottom: env(safe-area-inset-bottom);
border-top: 1rpx solid #ededed;
.tips {
margin: 20rpx;
text-align: center;
font-size: 27rpx;
color: #a6a6a6;
}
.footer-button {
padding: 0 30rpx;
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
justify-content: space-between;
view {
width: 330rpx;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
background-color: #f7f7f7;
}
.confirm {
color: #fff;
background: jeepay-bg-primary;
}
}
}
}
}
</style>

View File

@ -1,57 +0,0 @@
<template>
<!-- 单元格布局 -->
<view
class="cell-main"
:hover-class="isTouch ? 'touch-hover' : ''"
:style="{ '--border-width': borderWidth, marginTop: mT + 'rpx', '--m-rl': mRL + 'rpx', backgroundColor: bgColor }"
>
<view class="title" :style="{ color: color }"> {{ title }} </view>
<slot name="right">
<image src="/static/iconImg/icon-arrow-right.svg" mode="scaleToFill" />
</slot>
</view>
</template>
<script setup>
const props = defineProps({
title: { type: String }, //
mT: { type: Number }, //
mRL: { type: Number }, //
bgColor: { type: String }, //
color: { type: String }, //
borderWidth: { type: String, default: '100vw' }, // 100vw
isTouch: { type: Boolean, default: true }, //
})
</script>
<style lang="scss" scoped>
.cell-main {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
margin-left: var(--m-rl);
margin-right: var(--m-rl);
height: 120rpx;
.title {
margin-left: 40rpx;
font-size: 32rpx;
font-weight: 400;
}
image {
width: 120rpx;
height: 120rpx;
}
background-color: #fff;
&::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
z-index: 10;
width: calc(100vw - var(--border-width));
height: 1rpx;
background-color: #ededed;
}
}
</style>

View File

@ -1,65 +0,0 @@
<template>
<template v-if="subTitle">
<view class="details-wrapper" style="align-items: flex-start; padding-top: 40rpx">
<view class="details-title">{{ title }}</view>
<view>
<view class="sub-title">
<view class="details-info single-text-beyond"> {{ subTitle }}</view>
<image src="/static/iconImg/icon-arrow-small.svg" mode="scaleToFill" />
</view>
<view class="sub-info details-info single-text-beyond">{{ info }}</view>
</view>
</view>
</template>
<template v-else>
<view class="details-wrapper">
<view class="details-title">{{ title }}</view>
<view class="details-info single-text-beyond">{{ info }}</view>
<image src="/static/iconImg/icon-arrow-right.svg" mode="scaleToFill" />
</view>
</template>
</template>
<script setup>
const props = defineProps({
title: { type: String }, //
info: [String, Number], //
subTitle: { type: String }, //
})
</script>
<style lang="scss" scoped>
.details-wrapper {
display: flex;
align-items: center;
padding-left: 40rpx;
min-height: 120rpx;
font-size: 30rpx;
background-color: #fff;
.details-title {
width: 200rpx;
color: #4c4c4c;
}
.details-info {
flex: 1;
width: 334rpx;
}
image {
width: 108rpx;
height: 120rpx;
}
}
.sub-title {
display: flex;
image {
width: 108rpx;
height: 40rpx;
}
}
.sub-info {
margin-top: 20rpx;
font-size: 30rpx;
color: #a1a1a1;
padding-bottom: 40rpx;
}
</style>

View File

@ -1,36 +0,0 @@
<template>
<!-- 详情页 带开关卡片布局 -->
<view class="s-wrapper">
<view class="s-title">
<text>{{ title }}</text>
<slot name="titleRight" />
</view>
<view class="s-tips">{{ subTitle }}</view>
</view>
</template>
<script setup>
const props = defineProps({
title: { type: String }, //
subTitle: { type: String }, //
})
</script>
<style lang="scss" scoped>
.s-wrapper {
padding: 40rpx;
margin: 30rpx 35rpx;
border-radius: $J-b-r32;
background-color: #fff;
.s-title {
display: flex;
justify-content: space-between;
font-size: 30rpx;
color: #4d4d4d;
}
.s-tips {
font-size: 25rpx;
color: #808080;
}
}
</style>

View File

@ -1,164 +0,0 @@
<template>
<view class="k-wrapper">
<view class="k-store-name">
<view class="k-store-title flex-center">收款门店</view>
<view class="flex-center" @tap="emits('selectedStore')"> {{ storeName || '选择门店' }} <image src="/static/iconImg/icon-arrow-black.svg" mode="scaleToFill" /></view>
</view>
<view class="k-main">
<block v-for="(v, i) in keyList" :key="i">
<view :class="[v.clsName]" hover-class="touch-number" hover-stay-time="150" v-if="v.type == 'number'" @tap="boardDown(v.value)">{{ v.value }}</view>
<view :class="[v.clsName]" hover-class="touch-number" hover-stay-time="150" v-if="v.type == 'image'" @tap="boardDown(v.value)">
<image :src="v.imgUrl" mode="scaleToFill" />
</view>
<view :class="[v.clsName]" hover-class="touch-button" hover-stay-time="150" v-if="v.type == 'button'" @tap="boardDown(v.value)">
<image :src="v.imgUrl" mode="scaleToFill" />
<text>{{ v.text }}</text>
</view>
</block>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const emits = defineEmits(['boardDown', 'selectedStore',"update:value"])
/***
* 键盘渲染集合
* boardDown 回调事件 回调参数 value
* selectedStore 回调事件 选择门店 回调参数
* storeName 门店名称
* */
const props = defineProps({
storeName: { type: String }, //
point: { type: Number, default: 2 }, //
maxLength: { type: Number, default: 10 }, //
value:{type:[String,Number],default:'0'}
})
const keyList = reactive([
{ type: 'number', clsName: 'k-number', value: '1' },
{ type: 'number', clsName: 'k-number', value: '2' },
{ type: 'number', clsName: 'k-number', value: '3' },
{ type: 'number', clsName: 'k-number', value: '4' },
{ type: 'number', clsName: 'k-number', value: '5' },
{ type: 'number', clsName: 'k-number', value: '6' },
{ type: 'number', clsName: 'k-number', value: '7' },
{ type: 'number', clsName: 'k-number', value: '8' },
{ type: 'number', clsName: 'k-number', value: '9' },
{ type: 'number', clsName: 'k-number', value: '.' },
{ type: 'number', clsName: 'k-number k-zero', value: '0' },
{ type: 'image', clsName: 'k-number', value: 'deleted', imgUrl: '/static/iconImg/icon-delete.svg' },
{ type: 'button', clsName: 'k-button', value: 'scan', imgUrl: '/static/iconImg/icon-scan.svg', text: '扫一扫' },
{ type: 'button', clsName: 'k-button k-button-code', value: 'code', imgUrl: '/static/iconImg/icon-code.svg', text: '聚合码' },
])
const deletedNumber = () => {
emits('update:value', props.value.toString().slice(0, props.value.length - 1))
}
const boardDown = (val) => {
//
if (val == 'scan' || val == 'code') return emits('boardDown', val)
//
if (val == 'deleted') return deletedNumber()
// 0
if (props.value.toString().length == 1 && props.value == 0 && val != '.') return emits('update:value', val)
//
if (props.value.toString().includes('.') && val == '.') return
//
if (props.value.toString().includes('.') && props.value.split('.')[1].length >= props.point) return
// return
if (props.value.toString().length == 1 && props.value == 0 && val != '.') return
// return
if ((props.value === '' || props.value == undefined) && val == '.') return emits('update:value', '0' + val)
// return
if (props.value.toString().length >= props.maxLength) return
//
emits('update:value', props.value + val)
}
</script>
<style lang="scss" scoped>
.k-wrapper {
padding: 0 10rpx;
border-radius: 72rpx 72rpx 0 0;
border-top: 1rps solid rgba($color: #000000, $alpha: 0.1);
box-shadow: 0 -30rpx 80rpx -20rpx rgba(0, 0, 0, 0.05);
.k-store-name {
display: flex;
align-items: center;
justify-content: space-between;
height: 110rpx;
margin: 10rpx 0;
padding: 0 60rpx;
view {
flex-grow: 0;
height: 100%;
font-size: 30rpx;
font-weight: 500;
image {
width: 40rpx;
height: 40rpx;
transform: rotate(180deg);
margin-left: 10rpx;
}
}
.k-store-title {
white-space: nowrap;
font-size: 30rpx;
font-weight: 400;
color: $J-color-t4d;
}
}
.k-main {
display: grid;
grid-template-columns: repeat(3, 200rpx);
grid-template-rows: repeat(5, 120rpx);
grid-gap: 10rpx 20rpx;
padding: 0 50rpx;
font-size: 60rpx;
border-radius: 30rpx 30rpx 0 0;
overflow: hidden;
.k-number {
display: flex;
justify-content: center;
align-items: center;
border-radius: 10rpx;
image {
width: 60rpx;
height: 60rpx;
}
}
.k-button {
grid-column: 1 / span 2;
grid-row: 5 / span 2;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20rpx;
width: 315rpx;
height: 110rpx;
background: $jeepay-bg-primary;
font-size: 26rpx;
border-radius: 10rpx;
color: #fff;
image {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
}
.k-button-code {
transform: translateX(335rpx);
background: linear-gradient(270deg, rgba(72, 192, 255, 1) 0%, rgba(51, 157, 255, 1) 100%);
}
.touch-number {
border-radius: 80rpx;
background-color: #e9eaeb;
}
.touch-button {
opacity: 0.5;
}
}
}
</style>

View File

@ -1,97 +0,0 @@
<template>
<view class="p-wrapper">
<input class="p-input" type="number" v-model="info" :focus="vdata.isFoucs" :maxlength="num" @input="inputChange" />
<view class="p-main" :style="{ margin: margin }">
<div class="p-number flex-center" v-for="v in num" :key="v" :class="{ 'p-active': v <= info.length }"></div>
</view>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
const emits = defineEmits(['inputChange'])
const props = defineProps({
focus: { type: Boolean, default: false }, // false
num: { type: Number, default: 6 }, //
margin: { type: String }, //
})
const info = ref('')
const vdata = reactive({
isFoucs: false
})
onMounted(() => {
// 怀 nextTick使
// 1. 2. input.
if(props.focus){
setTimeout(() => {vdata.isFoucs = true}, 500)
}
})
const clearInput = () => (info.value = '')
const inputChange = () => {
emits('inputChange', info.value)
}
defineExpose({ clearInput })
</script>
<style lang="scss" scoped>
.p-wrapper {
position: relative;
width: 100%;
height: 80rpx;
overflow: hidden;
&::after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
z-index: 10;
width: 95rpx;
height: 100%;
}
&::before {
content: '';
display: block;
position: absolute;
top: 0;
right: 0;
z-index: 10;
width: 95rpx;
height: 100%;
}
.p-input {
position: absolute;
top: 10%;
left: -100vw;
right: 0;
opacity: 0;
color: transparent;
caret-color: transparent;
}
.p-main {
display: flex;
justify-content: space-between;
margin: 0 95rpx;
.p-number {
width: 80rpx;
height: 80rpx;
border-radius: 12rpx;
background-color: #f2f2f2;
}
.p-active::after {
content: '';
display: block;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background-color: #000;
}
}
}
</style>

View File

@ -1,53 +0,0 @@
<template>
<view class="search-wrapper" :style="{ paddingTop: pTop + 'rpx', backgroundColor: bgColor }">
<view class="search-main" @tap="emits('click')">
<image src="/static/iconImg/icon-search.svg" mode="scaleToFill" />
<input type="text" :placeholder="place" placeholder-style="color: rgba(0,0,0,0.35);" :style="{ fontSize: size + 'rpx' }" disabled />
</view>
<slot name="right" />
</view>
</template>
<script setup>
const props = defineProps({
place: { type: String }, //
pTop: { type: Number }, // 使padding
bgColor: { type: String }, //
size: { type: Number, default: 27 }, //
})
const emits = defineEmits(['click'])
</script>
<style lang="scss" scoped>
.search-wrapper {
display: flex;
align-items: center;
height: 110rpx;
background-color: $J-bg-ff;
padding: 0 30rpx;
.search-main {
flex: 1;
display: flex;
align-items: center;
height: 70rpx;
background-color: $J-bg-f5;
border-radius: $J-b-r12;
image {
padding: 0 22rpx;
width: 26rpx;
height: 26rpx;
}
input {
flex: 1;
}
.search-text {
padding: 0 30rpx;
font-size: 32rpx;
font-weight: 500;
color: $J-color-t29;
}
}
}
</style>

View File

@ -1,116 +0,0 @@
<template>
<uni-popup ref="popup" type="bottom" mask-background-color="rgba(0,0,0,.5)" @change="change" :safe-area="false">
<view class="tips-wrapper">
<view class="tips-text flex-center" v-if="title">{{ title }}</view>
<scroll-view scroll-y class="list-wrap">
<block v-for="v in list" :key="v[value]">
<view
class="single-text flex-center"
hover-class="u-cell-hover"
hover-stay-time="150"
:style="{ color: v[value] == selected ? activeColor : v.color }"
@tap="confirm(v)"
>
{{ v[label] }}
</view>
</block>
</scroll-view>
<view class="line"></view>
<view class="tips-text tips-cancel flex-center" hover-class="u-cell-hover" hover-stay-time="150" @tap="popup.close()">取消</view>
</view>
</uni-popup>
<JeepayPopupConfirm ref="jeepayPopupConfirm" />
</template>
<script setup>
import { reactive, ref, inject } from 'vue';
const emits = defineEmits(['confirm']);
const props = defineProps({
title: { type: String }, //
activeColor: { type: String, default: '#2980FD' }, //
textColor: { type: String }, //
textSize: { type: String }, //
titleColor: { type: String }, //
titleSize: { type: String }, //
list: { type: Array }, //
label: { type: String, default: 'label' }, //
value: { type: String, default: 'value' } //key
});
const selected = ref(undefined);
const popup = ref(null);
const jeepayPopupConfirm = ref();
// val key
const open = (val) => {
selected.value = val;
popup.value.open();
};
const confirm = (listItem) => {
popup.value.close();
//
if (listItem.fun) {
//
if (listItem.confirmText) {
jeepayPopupConfirm.value
.open(listItem.confirmText)
.then(() => {
listItem.fun();
})
.catch(() => {
popup.value.open();
});
} else {
listItem.fun();
}
} else {
1;
emits('confirm', listItem);
}
};
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc');
const change = (e) => {
if (changePageMetaOverflowFunc) {
changePageMetaOverflowFunc(!e.show);
}
};
const close = () => popup.value.close();
defineExpose({ open, close });
</script>
<style lang="scss" scoped>
.list-wrap {
max-height: 60vh;
}
.tips-wrapper {
// overflow: hidden;
border-radius: 32rpx 32rpx 0 0;
padding-top: 20rpx;
padding-bottom: 60rpx;
background-color: #fff;
.tips-text {
text-align: center;
height: 90rpx;
font-size: 30rpx;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.07);
}
.single-text {
height: 120rpx;
}
.line {
height: 20rpx;
background-color: rgba(0, 0, 0, 0.07);
}
.tips-cancel {
height: 110rpx;
color: $J-color-t80;
font-size: 33rpx;
border: none;
}
.u-cell-hover {
background-color: #f8f9fa;
}
}
</style>

View File

@ -1,45 +0,0 @@
<template>
<switch :checked="flag" :disabled="disabled" color="#238FFC" :style="{ transform: 'scale(' + scale + ')', margin: margin }" @change="change" @tap="emits('click')" />
<JeepayPopupConfirm ref="jeepayPopupConfirmRef" />
</template>
<script setup>
import { ref, watchEffect } from 'vue'
const props = defineProps({
scale: { type: Number, default: 0.8 }, // .8
margin: { type: String, default: '0' }, // 0
tips: { type: String }, //使 tips
bol: { type: Boolean }, //
index: { type: Number, default: 0 }, //
confirmTips: { type: Boolean, default: true }, //
disabled: { type: Boolean, default: false }, //
})
const emits = defineEmits(['confirm', 'cancel', 'click'])
const flag = ref()
watchEffect(() => {
flag.value = props.bol
})
const jeepayPopupConfirmRef = ref() //
const change = (e) => {
flag.value = e.detail.value
if (!props.confirmTips) return confirm()
jeepayPopupConfirmRef.value
.open(props.tips || '确定修改状态?')
.then(() => {
confirm()
})
.catch(() => {
flag.value = !flag.value
emits('cancel', flag.value)
})
}
const confirm = () => {
emits('confirm', flag.value)
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,55 +0,0 @@
<template>
<view class="manage-main" :style="{ '--border-width': borderWidth }">
<view class="manage-title" :style="{ fontSize: titleSize, color: titleColor }">
{{ title }}
<slot name="right"></slot>
</view>
<view class="manage-info" :style="{ width: tipsWidth + 'rpx', fontSize: titleSize, color: titleColor }">{{ tips }}</view>
</view>
</template>
<script setup>
const props = defineProps({
title: { type: String }, //
tips: { type: String }, //
tipsWidth: { type: Number }, // 500rpx
titleSize: { type: Number }, //
tipsSize: { type: Number }, //
titleColor: { type: String }, //
tipsColor: { type: String }, //
borderWidth: { type: String, default: '40rpx' }, // 80rpx
})
</script>
<style lang="scss" scoped>
.manage-main {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0 40rpx;
height: 198rpx;
background-color: #fff;
&::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
z-index: 10;
width: calc(100vw - var(--border-width));
height: 1rpx;
background-color: #ededed;
}
.manage-title {
display: flex;
align-items: center;
justify-content: space-between;
color: #4d4d4d;
}
.manage-info {
margin-top: 12rpx;
width: 500rpx;
font-size: 25rpx;
color: #999999;
}
}
</style>

View File

@ -1,117 +0,0 @@
<template>
<scroll-view
class="table-list"
scroll-y
:style="{ '--height': height }"
@scrolltolower="addNext"
@refresherrefresh="openRefresh"
:refresher-enabled="refresh"
:refresher-triggered="vdata.isRefresh"
>
<template v-for="(record, i) in vdata.allData" :key="i">
<slot name="tableBody" :record="record" :index="i" />
</template>
<view class="list-null" v-if="!vdata.apiResData.hasNext && showListNull">暂无更多数据</view>
</scroll-view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app';
//
const props = defineProps({
reqTableDataFunc: { type: Function, default: () => {} },
searchData: { type: Object, default: () => {} }, //
pageSize: { type: Number, default: 10 }, //
initData: { type: Boolean, default: true }, // true
showListNull: { type: Boolean, default: true }, //
height: { type: String, default: '88rpx' }, // 使 scroll-view 100vh -
refresh: { type: Boolean, default: false } //
});
const vdata = reactive({
allData: [], // appweb app
//
apiResData: { total: 0, records: [] },
//
iPage: { pageNumber: 1, pageSize: props.pageSize },
//
isRefresh: false
});
onMounted(() => {
//
props.initData ? refTable(true) : undefined;
});
//
function refTable(isToFirst = false) {
if (isToFirst) {
//
vdata.iPage.pageNumber = 1;
vdata.allData = []; //
}
//
return props.reqTableDataFunc(Object.assign({}, vdata.iPage, props.searchData)).then(({ bizData }) => {
Object.assign(vdata.apiResData, bizData); //
if (bizData.records) {
bizData.records.forEach((r) => vdata.allData.push(r));
}
});
}
/** 追加下一页数据 **/
function addNext() {
// console.log('')
//
if (vdata.apiResData.hasNext) {
vdata.iPage.pageNumber++;
refTable(false);
}
}
//
const openRefresh = () => {
vdata.isRefresh = true;
refTable(true).then(() => {
setTimeout(() => {
vdata.isRefresh = false;
}, 300);
});
};
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ refTable, addNext });
</script>
<style lang="scss" scoped>
.table-list {
height: calc(75vh - var(--height));
}
.list-null {
position: relative;
height: 110rpx;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 70rpx;
gap: 20rpx;
font-size: 26rpx;
color: #a6a6a6;
&::after,
&::before {
content: '';
display: block;
width: 30%;
height: 2rpx;
background-color: #ededed;
transform: translateY(-50%);
}
}
</style>

View File

@ -1,58 +0,0 @@
<template>
<uni-popup ref="popup" type="bottom" mask-background-color="rgba(0,0,0,.5)" @change='change' :safe-area="false" @maskClick="emits('cancel')">
<!-- 通用提示弹窗 用于提示用户 数据含义 -->
<view class="card-wrapper">
<view class="card-title flex-center">{{ title }}</view>
<slot />
<view class="card-button flex-center" hover-class="touch-hover" @tap="confirm"> {{ buttonText }}</view>
</view>
</uni-popup>
</template>
<script setup>
import { onMounted, reactive, ref,inject } from 'vue'
const emits = defineEmits(['cancel'])
const props = defineProps({
title: { type: String }, //
buttonText: { type: String }, //
})
const popup = ref(null)
const open = (val) => {
popup.value.open()
}
const confirm = () => {
emits('cancel')
popup.value.close()
}
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc')
const change = (e)=>{
if(changePageMetaOverflowFunc){
changePageMetaOverflowFunc(!e.show)
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.card-wrapper {
border-radius: 32rpx 32rpx 0 0;
background-color: #fff;
padding-bottom: 60rpx;
max-height: 70vh;
.card-title {
margin-bottom: 20rpx;
height: 110rpx;
font-size: 30rpx;
font-weight: 400;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.07);
}
.card-button {
margin-top: 20rpx;
height: 110rpx;
font-size: 32rpx;
color: #2980fd;
border-top: 20rpx solid #f7f7f7;
}
}
</style>

View File

@ -1,53 +0,0 @@
<template>
<!-- 单张广告 -->
<view class="ad-wrapper" v-if="list.length == 1">
<image :src="list[0].imgUrl" mode="aspectFill" @tap='toH5(list[0].linkUrl)' />
</view>
<!-- 多张广告 -->
<view class="ads-wrapper" v-else>
<block v-for="(v, i) in list" :key="i">
<view>
<image :src="v.imgUrl" mode="aspectFill" @tap='toH5(v.linkUrl)' />
</view>
</block>
</view>
</template>
<script setup>
const props = defineProps({
list: { type: Array, default: [] }
})
const toH5 = (url) => {
if (!url) return
uni.navigateTo({
url: '/pages/adH5/adH5?url=' + url
})
}
</script>
<style lang="scss" scoped>
.ad-wrapper {
margin: 40rpx;
max-height: 680rpx;
border-radius: 30rpx;
overflow: hidden;
}
.ads-wrapper {
display: flex;
justify-content: space-between;
margin: 30rpx;
view {
width: calc(50% - 20rpx);
max-height: 400rpx;
border-radius: 30rpx;
overflow: hidden;
}
}
image {
width: 100%;
}
</style>

View File

@ -1,237 +0,0 @@
<template>
<view class="start" v-if="show">
<view class="skip" :style="skipPositionStyle" @click="onSkip">跳过 {{ time2 }}</view>
<swiper class="swiper" :interval="interval" :autoplay="list.length > 1" @change="onChangeSwiper">
<swiper-item v-for="(item, index) in list" :key="index">
<view class="swiper-item" :style="bgStyle">
<image class="image" :src="item.imgUrl" mode="aspectFill" @tap="toAdH5(item)"></image>
<view class="after" :style="afterStyle"></view>
</view>
</swiper-item>
<!-- autoplay -->
</swiper>
<view class="swiper-dot" v-if="list.length > 1">
<view class="view" :style="index === current ? currentStyle : ''" :class="{ active: index === current }"
v-for="(item, index) in list" :key="index" />
</view>
</view>
</template>
<script>
export default {
props: {
list: {
type: Array,
default() {
return []
},
required: true,
},
hasTabbar: {
type: Boolean,
default: false,
},
hasNavbar: {
type: Boolean,
default: false,
},
interval: {
type: Number,
default: 3000,
},
time: {
type: Number,
default: 3,
},
url: {
type: String,
default: '',
},
bgColor: {
type: String,
default: '#fff',
},
afterColor: {
type: String,
default: '',
},
currentColor: {
type: String,
default: '#BB1219',
},
},
data() {
return {
current: 0,
show: true,
timer: null,
time2: this.time,
}
},
watch: {
time2(val) {
if (val <= 0) {
this.onSkip()
}
},
},
computed: {
bgStyle() {
return this.obj2strStyle({
'background-color': this.bgColor,
})
},
afterStyle() {
return this.obj2strStyle({
'background-color': this.afterColor,
})
},
currentStyle() {
return this.obj2strStyle({
'background-color': this.currentColor,
})
},
skipPositionStyle() {
const { statusBarHeight } = uni.getSystemInfoSync()
if (!this.hasNavbar) {
return this.obj2strStyle({
top: `${statusBarHeight * 2 + 88 + 30}rpx`,
})
}
return this.obj2strStyle({
top: '30rpx',
})
},
},
created() {
this.$emit('openInt', this.onStart)
},
mounted() {
if (this.hasTabbar) {
uni.hideTabBar()
}
},
methods: {
onStart() {
this.timer = setInterval(() => {
this.time2--
}, 1000)
},
onPause() {
clearInterval(this.timer)
},
obj2strStyle(obj) {
let style = ''
for (let key in obj) {
style += `${key}:${obj[key]};`
}
return style
},
onSkip() {
const { url, hasTabbar, timer } = this
clearTimeout(timer)
this.show = false
if (hasTabbar) {
uni.showTabBar()
}
if (url) {
uni.reLaunch({
url: url,
})
}
},
onChangeSwiper(e) {
this.current = e.detail.current
},
toAdH5(ite) {
if (!ite.linkUrl) return
clearInterval(this.timer)
uni.navigateTo({
url: '/pages/adH5/adH5?url=' + ite.linkUrl,
})
},
},
}
</script>
<style scoped>
/* $nav-height: 44px; */
.start {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
}
.skip {
position: absolute;
z-index: 2;
background-color: rgba(0, 0, 0, 0.1);
color: #fff;
right: 30rpx;
font-size: 28rpx;
width: 133rpx;
height: 60rpx;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
}
.swiper {
height: 100vh;
width: 100vw;
}
.swiper-item {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
background-color: transparent;
}
.swiper-item .after {
width: 100vw;
height: 500rpx;
position: absolute;
left: 0;
bottom: 0;
z-index: 1;
}
.swiper-item .image {
height: 100vh;
width: 100vw;
display: block;
position: relative;
z-index: 2;
}
.swiper-dot {
position: absolute;
width: 100vw;
left: 0;
bottom: 100rpx;
z-index: 3;
display: flex;
justify-content: center;
}
.swiper-dot .view {
width: 16rpx;
height: 16rpx;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.2);
margin: 0 12rpx;
}
.swiper-dot .view.active {
width: 30rpx;
border-radius: 24rpx;
}
</style>

View File

@ -1,118 +0,0 @@
<!--
背景模板
使用方式
A. 背景图片的通用外部view APP不支持背景图片的变量动态替换 所以只能业务页面来写入背景图片的地址
<JeepayBackground :bgImgView="true">页面内容</JeepayBackground>
<style scoped>
/deep/ .bg-img-view { background: url('/static/indexImg/user-bg.svg'); }
</style>
B. 背景是自定义颜色的外部view ( 默认蓝色渐变 )
<JeepayBackground :bgColorStyle="{}">页面内容</JeepayBackground>
@author terrfly
@site https://www.jeequan.com
@date 2022/11/19 08:08
-->
<template>
<!-- 微信小程序 <page-meta>: 只能是页面内的第一个节点且不能被 wx:if wx:for 动态变更
uniapp: 打包到小程序 会添加 <jeepay-background>标签 导致该问题 无奈 小程序不可使用 <page-meta> 标签 实现方式为 page-wrapper height方式
-->
<!-- <page-meta :pageStyle="'overflow:' + (vdata.pageMetaOverflow ? 'visible' : 'hidden')"></page-meta> -->
<!-- #ifdef APP-PLUS-->
<page-meta :pageStyle="'overflow:' + (vdata.pageMetaOverflow ? 'visible' : 'hidden')"></page-meta>
<!-- #endif -->
<!-- page-wrapper 包裹 -->
<view class="page-wrapper" :style="{overflow:vdata.pageMetaOverflow ? 'visible' : 'hidden', height:vdata.pageMetaOverflow ? 'auto' : '90vh'}">
<!-- 背景图片view -->
<view class="bg-img-view" :style="vdata.bgImgStyle">
<!-- 背景颜色view -->
<view class="bg-color-view" :style="vdata.bgColorStyle" style="border-radius:0;background-color: #318AFE!important;">
<view class="bgbottomStyle">
</view>
</view>
<!-- 解决定位层级问题 -->
<view class="bg-main">
<slot></slot>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref, onMounted, provide, computed } from 'vue'
//
const props = defineProps({
//
bgImgView: { type: Boolean }, // APP
// style
bgColorStyle: { type: Object },
// 穿
})
function changePageMetaOverflowFunc(v){
vdata.pageMetaOverflow = v
}
provide('changePageMetaOverflowFunc', changePageMetaOverflowFunc)
const vdata = reactive({
bgImgStyle : { }, // style 使Object.assign, APP
bgColorStyle : { },
pageMetaOverflow: true
})
provide('pageMetaOverflow',computed(()=>vdata.pageMetaOverflow))
onMounted(() => {
//
if(props.bgImgView){
vdata.bgImgStyle = {
position: "absolute",
top: 0,
left: 0,
right: 0,
backgroundRepeat: 'no-repeat'
}
}
//
if(props.bgColorStyle){
let defStyle = { //
position: "absolute",
top: 0,
left: 0,
right: 0,
height: '550rpx',
borderRadius: '0 0 32rpx 32rpx',
// background: 'linear-gradient(270deg, rgba(72, 192, 255, 1) 0%, rgba(51, 157, 255, 1) 100%)',
}
vdata.bgColorStyle = Object.assign(defStyle, props.bgColorStyle)
}
})
</script>
<style scoped lang="scss">
.bg-main{
position: relative;
z-index: 10;
}
.bgbottomStyle{
position: absolute;
bottom: -2rpx;
left: 0;
width: 750rpx;
height: 74rpx;
background: linear-gradient( 180deg, rgba(195,215,235,0) 0%, #F9F9F9 100%);
}
</style>

View File

@ -1,55 +0,0 @@
<template>
<swiper
class="swiper"
circular
:indicator-dots="true"
autoplay
:interval="interval * 1000"
:duration="500"
>
<block v-for="(v, i) in list" :key="i">
<swiper-item>
<image :src="v.imgUrl" mode="aspectFill" @tap="toH5(v.linkUrl)" />
</swiper-item>
</block>
</swiper>
</template>
<script setup>
const props = defineProps({
list: { type: Array, default: [] },
interval: { type: [String, Number] },
});
const toH5 = (url) => {
if (!url) return;
uni.navigateTo({
url: '/pages/adH5/adH5?url=' + url,
});
};
</script>
<style lang="scss" scoped>
.uni-margin-wrap {
width: 690rpx;
width: 100%;
}
.swiper {
margin: 40rpx;
height: 300rpx;
border-radius: 30rpx;
overflow: hidden;
}
.swiper-item {
display: block;
height: 300rpx;
line-height: 300rpx;
text-align: center;
}
image {
width: 100%;
}
</style>

View File

@ -1,143 +0,0 @@
<!--
Jeepay 门店选择 / 应用选择
@author terrfly
@site https://www.jeequan.com
@date 2022/12/06 12:55
-->
<template>
<!-- 选择门店 -->
<JeepayPopupListSelect
ref="jeepayPopupListSelectByBizinfos"
:reqTableDataFunc="reqTableDataByBizsFunc"
:searchInputName="getSearchInputName()"
:fields="getField()"
:isCheckbox="props.isCheckbox"
:addUse="props.addUse"
@confirm="confirm"
/>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { reqLoad, API_URL_MCH_STORE_LIST, API_URL_MCH_APP_LIST, API_URL_MCH_ISV_LIST } from '@/http/apiManager.js';
//
const props = defineProps({
configMode: '',
//
isCheckbox: { type: Boolean, default: false },
//
autoClose: { type: Boolean, default: true },
//
bizType: { type: String, default: 'store' },
range: { type: String, default: 0 },
ifCode: { type: String, default: '' },
//
isShowAllBiz: { type: Boolean, default: false },
//
params: { type: Object, default: () => ({}) },
addUse: { type: Boolean, default: false }
});
const jeepayPopupListSelectByBizinfos = ref();
const emits = defineEmits(['confirm']);
function confirm(data) {
console.log(data);
emits('confirmData', data);
}
console.log(props.isCheckbox);
function getField() {
if (props.bizType == 'store') {
return { key: 'storeId', left: 'storeName', right: 'storeId' };
}
if (props.bizType == 'mchApp') {
return { key: 'appId', left: 'appName', right: 'appId' };
}
if (props.bizType == 'isvApp') {
return { key: 'isvNo', left: 'isvName', right: 'isvNo' };
}
}
function getSearchInputName() {
if (props.bizType == 'store') {
return 'storeName';
}
if (props.bizType == 'mchApp') {
return 'appName';
}
if (props.bizType == 'isvApp') {
return 'isvName';
}
}
function reqTableDataByBizsFunc(params) {
Object.assign(params, props.params);
console.log(params);
let apiResult = null;
if (props.bizType == 'store') {
apiResult = reqLoad.list(API_URL_MCH_STORE_LIST, params);
}
if (props.bizType == 'mchApp') {
apiResult = reqLoad.list(API_URL_MCH_APP_LIST, params);
}
if (props.bizType == 'isvApp') {
params.ifCode = props.ifCode;
params.range = props.range;
apiResult = reqLoad.list(API_URL_MCH_ISV_LIST, params);
}
return apiResult.then((apiRes) => {
return processApiResBizData(params, apiRes);
});
}
//
function open(defaultVal) {
console.log(defaultVal, 'defaultValdefaultVal');
return jeepayPopupListSelectByBizinfos.value.open(defaultVal).then((selected) => {
//
if (props.autoClose) {
close();
}
return selected;
});
}
function close() {
jeepayPopupListSelectByBizinfos.value.close(); //
}
function processApiResBizData(params, apiRes) {
// (index = 0 )
if (params.pageNumber == 1 && props.isShowAllBiz) {
if (props.bizType == 'store') {
apiRes.bizData.records.unshift({ storeName: '全部门店', storeId: '' });
}
if (props.bizType == 'mchApp') {
apiRes.bizData.records.unshift({ appName: '全部应用', appId: '' });
}
if (props.bizType == 'isvApp') {
apiRes.bizData.records.unshift({ appName: '全部渠道', appId: '' });
}
}
return apiRes;
}
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open, close });
</script>
<style></style>

View File

@ -1,144 +0,0 @@
<!--
通用的选择某项业务 一般用作修改页
目前支持 门店 应用
@author terrfly
@site https://www.jeepay.vip
@date 2022/12/08 14:18
-->
<template>
<view class="details-wrapper" style="align-items: flex-start; padding-top: 40rpx">
<view v-if="props.hasTitle" class="details-title">
<slot name="title">{{ bizTypeMap[props.bizType].title }}</slot>
</view>
<view @tap="show">
<view class="sub-title">
<view class="details-info single-text-beyond">
<text :class="{ 'text-gray': vdata.selectedRow[bizTypeMap[props.bizType].nameKey] ? false : true }">
{{ vdata.selectedRow[bizTypeMap[props.bizType].nameKey] || bizTypeMap[props.bizType].nameDef }}
</text>
</view>
<image src="/static/iconImg/icon-arrow-small.svg" mode="scaleToFill" v-if="isIcon" />
</view>
<view class="sub-info details-info single-text-beyond">{{ vdata.selectedRow[bizTypeMap[props.bizType].id] }}</view>
</view>
</view>
<view>
<JeepayBizinfoSelect ref="jeepayBizinfoSelectRef" :bizType="props.bizType" :isCheckbox="false" :range="props.range" :ifCode="props.ifCode" :addUse="props.addUse" />
<JeepayIncomingBizinfoSelect ref="jeepayIncomingBizinfoSelectRef" :bizType="props.bizType" :range="props.range" :ifCode="props.ifCode" />
</view>
</template>
<script setup>
import { ref, reactive, nextTick, watch, onMounted } from 'vue';
const jeepayBizinfoSelectRef = ref();
const jeepayIncomingBizinfoSelectRef = ref();
const bizTypeMap = {
store: { title: '选择门店', nameKey: 'storeName', nameDef: '请选择门店', id: 'storeId' },
mchApp: { title: '选择应用', nameKey: 'appName', nameDef: '请选择应用', id: 'appId' },
isvApp: { title: '选择渠道', nameKey: 'isvName', nameDef: '请选择渠道', id: 'isvNo' },
incomingApp: { title: '发起进件', nameKey: 'name', nameDef: '请选择场景', id: 'range' }
};
// emit 使 v-model:value="val"
const emits = defineEmits(['update:value', 'update:showName', 'change']);
const props = defineProps({
//
hasTitle: { type: Boolean, default: true },
//
value: { type: [String, Number] },
//
showName: { type: [String, Number] },
//
bizType: { type: String, default: 'store' },
range: { type: String, default: 0 },
ifCode: { type: String, default: '' },
isIcon: { type: Boolean, default: true },
addUse: { type: Boolean, default: false }
});
onMounted(() => {
if (props.value) {
vdata.selectedRow[bizTypeMap[props.bizType].id] = props.value;
}
if (props.showName) {
vdata.selectedRow[bizTypeMap[props.bizType].nameKey] = props.showName;
}
});
//
watch(
() => props.value,
(newVal, oldVal) => {
vdata.selectedRow[bizTypeMap[props.bizType].id] = newVal;
}
);
//
watch(
() => props.showName,
(newVal, oldVal) => {
vdata.selectedRow[bizTypeMap[props.bizType].nameKey] = newVal;
}
);
const vdata = reactive({
//
selectedRow: {}
});
function show() {
jeepayBizinfoSelectRef.value.open().then((selectedRow) => {
vdata.selectedRow = selectedRow || {};
emits('update:value', vdata.selectedRow[bizTypeMap[props.bizType].id]);
emits('update:showName', vdata.selectedRow[bizTypeMap[props.bizType].nameKey]);
emits('change', vdata.selectedRow[bizTypeMap[props.bizType].id]);
});
}
</script>
<style lang="scss" scoped>
.details-wrapper {
display: flex;
align-items: center;
font-size: 32rpx;
background-color: #fff;
.details-title {
width: 180rpx;
color: #4c4c4c;
}
.details-info {
flex-grow: 1;
width: 405rpx;
}
image {
width: 108rpx;
height: 100rpx;
}
.sub-title {
flex: 1;
display: flex;
image {
width: 108rpx;
height: 40rpx;
}
}
.sub-info {
margin-top: 20rpx;
font-size: 30rpx;
color: #a1a1a1;
padding-bottom: 20rpx;
}
.text-gray {
color: #b3b3b3;
}
}
</style>

View File

@ -1,90 +0,0 @@
<!--
组件功能 卡片布局
标题 副标题 和编辑按钮及插槽
注意 不包含 中间的内容
@author terrfly
@site https://www.jeequan.com
@date 2022/12/06 08:06
-->
<template>
<view class="c-card-wrapper" :style="props.viewStyle">
<view v-if="props.title" class="card-title" :class="{'border-none':!isTitleBorder}" @tap="emits('clickTitle')">
<view class="c-card-title"> {{ props.title }} <view><slot name="titleRight"/> </view> </view>
<view class="sub-title" v-if="props.subtitle">{{ props.subtitle }}</view>
</view>
<!-- 默认插槽位置 -->
<slot></slot>
<!-- 编辑区域 -->
<slot name="editContent">
<view v-if="props.editText" class="card-edit flex-center" hover-class="touch-hover" @tap="emits('editTap')">
<image src="/pageDevice/static/devIconImg/icon-edit.svg" mode="scaleToFill" /> {{ props.editText }}
</view>
</slot>
</view>
</template>
<script setup>
import { reactive, ref, onMounted, watch } from 'vue'
const emits = defineEmits(['editTap','clickTitle'])
const props = defineProps({
viewStyle: { type: [String, Object] }, // style()
title: { type: String }, //
subtitle: { type: String }, //
editText: { type: String }, // , editTap
isTitleBorder:{type:Boolean, default:true} //
})
</script>
<style lang="scss" scoped>
.c-card-wrapper {
margin: 0 35rpx;
border-radius: 32rpx;
background-color: #fff;
overflow: hidden;
.card-title {
display: flex;
flex-direction: column;
justify-content: center;
padding: 30rpx 40rpx;
min-height: 42rpx;
font-size: 32rpx;
font-weight: 500;
border-bottom: 1rpx solid #ededed;
.c-card-title{
display: flex;
justify-content: space-between;
}
.sub-title {
margin-top: 15rpx;
font-size: 25rpx;
color: #808080;
}
}
.card-edit {
height: 110rpx;
border-top: 1rpx solid #ededed;
color: #2980fd;
font-size: 33rpx;
font-weight: 400;
image {
width: 44rpx;
height: 44rpx;
margin-right: 10rpx;
}
}
}
.border-none{
border: none !important;
}
</style>

View File

@ -1,80 +0,0 @@
<!--
组件功能 解决原生组件双向绑定问题
@author terrfly
@site https://www.jeequan.com
@date 2022/11/18 14:32
-->
<template>
<view class="select-box" @click="changeFunc">
<button class="agree-item" id="agree-btn" open-type="agreePrivacyAuthorization"
@agreeprivacyauthorization="handAgree">
<image v-if="props.checked" class="select-img" src="@/static/login/selected.svg"></image>
<image v-else class="select-img" src="@/static/login/select.svg"></image>
</button>
</view>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
// emit 使 v-model="val"
const emit = defineEmits(['update:checked'])
onMounted(() => {
// #ifdef MP-WEIXIN
getPrivacy()
// #endif
})
//
const props = defineProps({
checked: { type: Boolean, default: false },
})
const vdata = reactive({})
function changeFunc () {
emit('update:checked', !props.checked)
}
//
const getPrivacy = () => {
wx.getPrivacySetting({
success: (r) => {
Object.assign(vdata, r)
if (vdata.needAuthorization) {
wx.onNeedPrivacyAuthorization(res => {
vdata.resolve = res
})
}
}
})
}
const handAgree = () => {
// #ifdef MP-WEIXIN
if (vdata.needAuthorization) {
vdata.resolve({ buttonId: 'agree-btn', event: 'agree' })
}
// #endif
}
</script>
<style scoped lang="scss">
.select-box {
display: inline;
.select-img {
width: 46rpx;
height: 46rpx;
}
}
.agree-item {
padding: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
line-height: 0;
width: 46rpx;
height: 46rpx;
border-radius: 0;
background-color: transparent;
}
</style>

View File

@ -1,159 +0,0 @@
<!--
组件功能 自定义导航栏包裹 , 基于 uni-nav-bar 的封装
1. pages.json : "navigationStyle": "custom"
2. 页面引入该组件
3. 如果背景透明并且需要下滑变默认背景色 需要在页面实现 onPageScroll函数可以空函数 否则该组件无法正常监听
示例
背景通铺效果
<JeepayCustomNavbar :transparent="true" bgDefaultColor='#b6a3a3' title="背景通铺效果" backCtrl="back" ></JeepayCustomNavbar>
import { onPageScroll } from '@dcloudio/uni-app'
onPageScroll(() => {})
纯色导航条
<JeepayCustomNavbar :transparent="false" bgDefaultColor='#ffaa7f' title="纯色导航条" backCtrl="back"></JeepayCustomNavbar>
自定义左上角 效果
<JeepayCustomNavbar :transparent="true" bgDefaultColor='#ff557f' title="自定义左上角" backCtrl="back">
<view> 选择门店自定义导航条内容 </view>
</JeepayCustomNavbar>
@author terrfly
@site https://www.jeequan.com
@date 2022/11/18 14:32
-->
<template>
<view>
<uni-nav-bar
fixed
:statusBar="true"
:border="false"
:height="props.height"
:backgroundColor="vdata.backgroundColor"
leftWidth="100%"
>
<!-- 使用左侧插槽 100%宽度 -->
<template #left>
<view class="left-slot-view">
<slot>
<view class="nav-bar-box">
<view>
<!-- 左侧按钮 -->
<uni-icons v-if="props.backCtrl" class="left-back" @click="backFunc" :type="props.backIcon" size="20" :color="props.textColor"></uni-icons>
</view>
<!-- 标题 -->
<view class="text" :style="{ color: props.textColor }"> {{props.title}} </view>
</view>
</slot>
</view>
</template>
</uni-nav-bar>
</view>
</template>
<script setup>
import { onPageScroll } from '@dcloudio/uni-app'
import { reactive, ref, onMounted } from 'vue'
import ak from '@/commons/utils/ak.js'
//
const props = defineProps({
//
title: { type: String, default: '' },
//
textColor: { type: String, default: 'black' },
//
backIcon: { type: String, default: 'back' },
// uni-nav-bar
height: { type: Number, default: 44 },
//
bgDefaultColor: { type: String, default: 'white' },
//
transparent: { type: Boolean, default: false },
// null- back pageUrl: '',
backCtrl: [ String, Function ],
})
//
if(props.transparent){
onPageScroll((e) => { // or
if(e.scrollTop > (props.height / 2.5) ){
vdata.backgroundColor = props.bgDefaultColor
}else{
vdata.backgroundColor = 'transparent'
}
})
}
//
const vdata = reactive({
backgroundColor: 'transparent' //
})
onMounted(() => {
//
if(!props.transparent){
vdata.backgroundColor = props.bgDefaultColor + '';
}
})
//
function backFunc(){
if(!props.backCtrl){
return false;
}
if(typeof props.backCtrl == 'function'){
return props.backCtrl()
}
if(props.backCtrl === 'back'){
return ak.go.back()
}
}
</script>
<style scoped lang="scss">
.left-slot-view {
display: flex;
align-items: center;
width: 100%;
height: 100%;
line-height: 100%;
font-size: 33rpx;
font-weight: 500;
.nav-bar-box {
display: flex;
flex-grow: 1;
justify-content: space-between;
.left-back {
position: absolute;
}
&::after {
content: "";
}
}
}
::v-deep.uni-navbar__header {
.uni-navbar__header-container,
.uni-navbar__header-btns-right {
display: none !important;
}
}
</style>

View File

@ -1,32 +0,0 @@
<!--
描述信息展示
通用信息
@author terrfly
@site https://www.jeequan.com
@date 2022/12/06 10:11
-->
<template>
<view class="c-desc-view">
<slot></slot>
</view>
</template>
<script setup>
const props = defineProps({
})
</script>
<style lang="scss" scoped>
.c-desc-view {
}
</style>

View File

@ -1,77 +0,0 @@
<!--
描述信息展示
通用信息
@author terrfly
@site https://www.jeequan.com
@date 2022/12/06 10:11
-->
<template>
<view :class="{ 'c-desc-view-item': true, 'bottom-border': props.bottomBorder }">
<view class="title">
<slot name="title">{{ props.title }}</slot>
</view>
<view class="desc">
<slot name="desc">
<image v-if="props.descIsImg && props.desc" :src="props.desc" mode="scaleToFill" class="default-img" />
<template v-else>{{ props.desc }}</template>
</slot>
</view>
</view>
</template>
<script setup>
const props = defineProps({
//
title: { type: String },
//
desc: { type: String },
//
descIsImg: { type: Boolean, default: false },
//
bottomBorder: { type: Boolean, default: false }
});
</script>
<style lang="scss" scoped>
.c-desc-view-item {
display: flex;
justify-content: space-between;
padding: 20rpx 40rpx;
font-size: 30rpx;
font-weight: 400;
.title {
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 200rpx;
color: #808080;
}
.desc {
flex: 1;
text-align: right;
color: #000;
}
&:first-child {
margin-top: 20rpx;
}
&:last-child {
margin-bottom: 20rpx;
}
.default-img {
width: 150rpx;
height: 150rpx;
background-color: #f7f7f7;
}
}
.bottom-border {
padding-bottom: 40rpx;
border-bottom: 1rpx solid #ededed;
}
</style>

View File

@ -1,151 +0,0 @@
<!-- 待完成 -->
<template>
<view>
<slot></slot>
</view>
</template>
<script setup>
import { reactive, ref, onMounted, provide, computed } from 'vue'
import infoBox from '@/commons/utils/infoBox.js'
//
const props = defineProps({
//
rules: { type: Object, default: () => { } },
//
model: { type: Object, default: () => { } },
})
const vdata = reactive({
formNameList: [], // form
errorListByText: [], // ( )
errorListByToast: [], // ( alert )
})
//
function itemSign(name){
if(vdata.formNameList.indexOf(name) < 0){
vdata.formNameList.push(name)
}
}
//
function unItemSign(name){
if(vdata.formNameList.indexOf(name) >= 0){
vdata.formNameList.splice(vdata.formNameList.indexOf(name), 1)
}
}
// { type: String, required: true, message: '', showToastError: false, validator: (rule, value) => {} }
// showTextError : true
// showToastError: alert false
// {name, value, rule, errorMsg}
// errorMsg rule message errorMsg
function pushError(name, value, errorMsg, rule){
// false, true()
if(rule.showTextError === false){
}else{
vdata.errorListByText.push({name, value, rule, errorMsg})
}
// alert false
if(rule.showToastError === true){
vdata.errorListByToast.push({name, value, rule, errorMsg})
}
}
function validateFormItem(name){
//
if(!name || !props.rules[name] ){
return false
}
// model
const value = props.model[name]
props.rules[name].forEach( rule => {
// &&
if(rule.required && (value == null || value == '' || typeof value == 'undefined')){
pushError(name, value, rule.message, rule)
}else{ // ||
if(rule.validator){ // promise
let validatorResult = rule.validator(rule, value)
if( validatorResult == true){ //
}else{ //
pushError(name, value, validatorResult, rule)
}
}
}
})
return false;
}
// , Promise
function validate(){
//
vdata.errorListByText = []
vdata.errorListByToast = []
vdata.formNameList.forEach(name => validateFormItem(name) )
if(vdata.errorListByToast && vdata.errorListByToast.length > 0){
infoBox.showToast(vdata.errorListByToast[0].errorMsg)
}
console.log(vdata.formNameList);
console.log(vdata.errorListByText);
console.log(vdata.errorListByToast);
if(vdata.errorListByText.length <= 0 && vdata.errorListByToast.length <= 0){
alert('成功')
}
}
//
const provideModel = {
itemSign: itemSign,
unItemSign: unItemSign,
}
provide('jeepayForm', computed( ()=> provideModel ) )
// provideModel errorListByText
provide('jeepayErrorListByText', computed( ()=> vdata.errorListByText ) )
defineExpose({ validate })
</script>
<style>
</style>

View File

@ -1,71 +0,0 @@
<template>
<view>
{{props.label}} : <slot></slot>
<view v-if="props.showErrorText && vdata.errorMsg">{{ vdata.errorMsg }}</view>
</view>
</template>
<script setup>
import { reactive, ref, onMounted, onUnmounted, provide, computed, inject, watch } from 'vue'
const jeepayFormInject = inject("jeepayForm")
const jeepayForm = jeepayFormInject.value
const jeepayErrorListByTextInject = inject("jeepayErrorListByText")
onMounted(() => {
jeepayForm.itemSign(props.name)
})
onUnmounted(() => {
jeepayForm.unItemSign(props.name)
})
//
const props = defineProps({
name: { type: String },
label: { type: String },
//
showErrorText: { type: Boolean, default: true },
})
const vdata = reactive({
errorMsg: null, //
})
//
function changeItemErrorMsg(itemErrorListByText){
vdata.errorMsg = null;
if(itemErrorListByText && itemErrorListByText.length > 0){
vdata.errorMsg = itemErrorListByText[0].errorMsg
}
}
watch(() => jeepayErrorListByTextInject.value, (newVal, oldVal) => {
if(!newVal){
return false;
}
changeItemErrorMsg(newVal.filter(r=> r.name == props.name))
}
)
//
provide('jeepayFormItemErrorMsg', computed( ()=> vdata.errorMsg ) )
</script>
<style>
</style>

View File

@ -1,42 +0,0 @@
<template>
<uni-easyinput
v-model="props.value" :type="props.type"
:placeholder="vdata.errorMsg || props.placeholder"
/>
</template>
<script setup>
import { reactive, ref, onMounted, onUnmounted, provide, computed, inject, watch } from 'vue'
const jeepayFormItemErrorMsgInject = inject("jeepayFormItemErrorMsg")
//
const props = defineProps({
placeholder: { type: String },
label: { type: String },
type: { type: String },
//
value: { type: [String, Number] }
})
const vdata = reactive({
errorMsg: null, //
})
watch(() => jeepayFormItemErrorMsgInject.value, (newVal, oldVal) => {
vdata.errorMsg = newVal
}
)
</script>
<style>
</style>

View File

@ -1,91 +0,0 @@
<!--
信息列表的预览页面 比如 通知消息的前几条等
通用信息
@author terrfly
@site https://www.jeequan.com
@date 2022/11/15 06:18
-->
<template>
<view class="notice-wrapper">
<view class="notice-title" v-if="props.tableTitle">
<view class="notice-news">{{ props.tableTitle }}</view>
<view class="notice-more flex-center" v-if="props.isShowMoreBtn" @tap="listviewClickFunc(true, null)">
更多<image src="/static/iconImg/icon-arrow-black.svg" mode="scaleToFill" /></view>
</view>
<block v-for="(v, i) in props.dataList" :key="i">
<view class="notice-main" hover-class="touch-hover" hover-stay-time="150" @tap="listviewClickFunc(false, v)">
<view class="notice-content single-text-beyond">{{ v[props.fields.title] }}</view>
<view class="notice-time">{{ v[props.fields.subtitle] }}</view>
</view>
</block>
</view>
</template>
<script setup>
const props = defineProps({
//
tableTitle: { type: String },
// { title, subtitle }
dataList: { type: Array, default: () => [] },
//
fields: { type: Object, default: {title: 'title', subtitle: 'subtitle'} },
//
isShowMoreBtn: { type: Boolean, default: true },
})
// touchDown touchMore
const emits = defineEmits(["click"])
function listviewClickFunc (isClickMore, record) {
emits('click', isClickMore, record)
}
</script>
<style lang="scss" scoped>
.notice-wrapper {
width: 680rpx;
margin: 0 auto;
background-color: $J-bg-ff;
border-radius: $J-b-r32;
.notice-title {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
height: 102rpx;
border-bottom: 1rpx solid #ededed;
.notice-news {
font-size: 32rpx;
font-weight: 500;
}
.notice-more {
font-size: 32rpx;
color: $J-color-t80;
image {
width: 42rpx;
height: 42rpx;
transform: rotate(90deg);
margin-left: 5rpx;
}
}
}
.notice-main {
padding: 30rpx;
height: 90rpx;
.notice-content {
margin-bottom: 16rpx;
font-size: 30rpx;
}
.notice-time {
font-size: 26rpx;
color: $J-color-ta6;
}
}
}
</style>

View File

@ -1,131 +0,0 @@
<!--
登录页专用文字上移样式行高宽度密码框与通用样式不一致
autoComplete="new-password"
-->
<template>
<div class="jee-input">
<div class="jee-text-up">
<a-input
ref="inputRef"
:type="inputPassword"
:value="value"
:required="isGoogle"
:disabled="props.disabled"
autoComplete="new-password"
@change="onChange($event)"
/>
<label @click="inputRef.focus()">{{ placeholder }}</label>
</div>
<div v-if="isPassword == 'password'" class="eyes" @click="changeEyes">
<!-- 密码框的小眼睛 -->
<eye-outlined v-if="!eyes" />
<eye-invisible-outlined v-else />
</div>
</div>
</template>
<script lang="ts" setup>
import { defineProps, ref } from 'vue'
// input
const inputRef = ref()
//
const props = defineProps({
value: { type: String, default: null },
placeholder: { type: String, default: '' },
isPassword: { type: String, default: 'text' }, //
isGoogle: { type: String, default: 'required' }, //
disabled: { type: Boolean, default: false } //
})
// nextTick(() => {
// // inputRef.value.focus()
// if(!props.value) {
// inputRef.value.blur()
// }
// // watch(() => props.value, () => {
// // })
// })
//
let eyes = ref(true)
let inputPassword = ref(props.isPassword)
const changeEyes = () => {
eyes.value = !eyes.value
eyes.value
? (inputPassword.value = 'password')
: (inputPassword.value = 'text')
}
const emit = defineEmits(['update:value'])
const onChange = (e) => emit('update:value', e.target.value)
</script>
<style scoped lang="less">
.jee-input {
position: relative;
.eyes {
position: absolute;
right: 0;
top: 0;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
}
}
//
.jee-text-up {
position: relative;
input {
outline: 0;
transition: all 0.2s ease;
height: 40px;
max-width: 300px;
}
input::-webkit-input-placeholder {
color: transparent;
font-size: 13px;
}
.placeShow::-webkit-input-placeholder {
color: #bfbfbf;
}
label {
margin-left: 6px;
position: absolute;
left: 0;
bottom: 13px;
padding: 0px 5px;
color: #bfbfbf;
font-size: 13px;
transition: all 0.2s ease;
border-radius: 3px;
line-height: 1;
display: flex;
justify-content: center;
align-items: center;
cursor: initial;
}
input:focus + label,
input:active + label,
input:valid + label {
font-weight: normal;
font-size: 12px;
letter-spacing: 0.05em;
text-align: left;
color: var(--ant-primary-color);
background: #fff; //
transform: translateY(-22px);
}
input:not(:focus) + label {
color: #b0afb3;
background: #fff;
}
}
</style>

View File

@ -1,110 +0,0 @@
<!--
通用 确认弹层
@author terrfly
@site https://www.jeequan.com
@date 2022/11/22 07:30
-->
<template>
<uni-popup ref="popup" type="bottom" @maskClick="cancelFunc" mask-background-color="rgba(0,0,0,.5)" @change='change' :safe-area="false">
<view class="tips-wrapper">
<view class="tips-text" :style="{ textIndent: vdata.title.length > 20 ? '2em' : 0 }"> {{ vdata.title }} </view>
<view class="tips-text tips-confirm" hover-class="u-cell-hover" hover-stay-time="150" :style="{color: vdata.confirmColor }" @tap="confirmFunc">
{{ vdata.confirmText || "确认" }}
</view>
<view class="line"></view>
<view class="tips-text tips-cancel" hover-class="u-cell-hover" hover-stay-time="150" @tap="cancelFunc">
{{ vdata.cancelText || "取消" }}
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, reactive,inject } from "vue"
const popup = ref(null) //
const tips = ref("") //
const vdata = reactive({
title: '',
confirmText: '',
cancelText: '',
confirmColor: '',
promiseObject: { },
})
function confirmFunc(){
popup.value.close()
vdata.promiseObject.resolve()
}
function cancelFunc(){
popup.value.close()
vdata.promiseObject.reject()
}
function open (title, confirmTextOrExtObject , cancelText ) {
vdata.title = title
vdata.confirmText = typeof confirmTextOrExtObject == "string" ? confirmTextOrExtObject : ''
vdata.cancelText = cancelText
if(typeof confirmTextOrExtObject == "object" ) {
Object.assign(vdata,confirmTextOrExtObject)
}
popup.value.open()
return new Promise( (resolve, reject) => {
vdata.promiseObject.resolve = resolve
vdata.promiseObject.reject = reject
})
}
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc')
const change = (e)=>{
if(changePageMetaOverflowFunc){
changePageMetaOverflowFunc(!e.show)
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.tips-wrapper {
overflow: hidden;
border-radius: 32rpx 32rpx 0 0;
padding-bottom: 60rpx;
background-color: #fff;
.tips-text {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
min-height: 110rpx;
line-height: 1.8;
padding: 30rpx;
box-sizing: border-box;
font-size: 30rpx;
}
.line {
height: 20rpx;
background-color: rgba(0, 0, 0, 0.07);
}
.tips-confirm {
display: flex;
justify-content: center;
align-items: center;
border-top: 1rpx solid rgba(0, 0, 0, 0.07);
color: #2980fd;
font-size: 33rpx;
}
.tips-cancel {
justify-content: center;
align-items: center;
color: $J-color-t80;
font-size: 33rpx;
}
.u-cell-hover {
background-color: #f8f9fa;
}
}
</style>

View File

@ -1,91 +0,0 @@
<!--
组件作用 单个输入框的弹层
输入框的弹出框 uni必须使用的是 组件方式 无法直接JS调起
//
示例
A: 一般用法
<JeepayPopupInput ref="ref" label="备注" :maxLength="3" v-model:value="vdata.payRemark" />
B: 自定义 校验规则
<JeepayPopupInput ref="ref" label="备注" :maxLength="3" v-model:value="vdata.payRemark" :rules="[ {required: true }, {pattern: '^(123)+$' } ]" />
@author terrfly
@site https://www.jeequan.com
@date 2022/11/17 10:46
-->
<template>
<uni-popup ref="popupRef" type="dialog">
<uni-popup-dialog :before-close="true" mode="input" :title="`请输入${props.label}`" @confirm="confirmFunc" @close="popupRef.close()">
<template #default>
<uni-forms ref="formRef" :rules="vdata.rules" :modelValue="vdata.formData">
<uni-forms-item label="" name="singleInputVal">
<uni-easyinput :inputBorder="false" type="text" v-model="vdata.formData.singleInputVal" :placeholder="`最多输入${props.maxLength}个字`" :maxlength="props.maxLength" />
</uni-forms-item>
</uni-forms>
</template>
</uni-popup-dialog>
</uni-popup>
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
//
const props = defineProps({
//
label: { type: String, default: '' },
//
value: [Number, String],
//
maxLength: { type: Number, default: 10 },
rules: { type: Array, default: () => [] },
})
// emit 使 v-model="val"
const emit = defineEmits(['update:value'])
// watch
watch(
() => props.value,
(newVal, oldVal) => {
vdata.formData.singleInputVal = newVal
}
)
const popupRef = ref()
const formRef = ref()
const vdata = reactive({
//
formData: { singleInputVal: '' },
//
rules: {
singleInputVal: { rules: props.rules },
},
})
//
function confirmFunc() {
formRef.value.validate().then(() => {
emit('update:value', vdata.formData.singleInputVal)
popupRef.value.close()
})
}
//
function open() {
vdata.formData.singleInputVal = props.value
popupRef.value.open()
}
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,361 +0,0 @@
<!--
组件作用 弹层 列表支持 单选 多选
使用方法
<JeepayPopupListSelect ref="jeepayPopupListSelect" :reqTableDataFunc="reqTableDataFunc" :fields="{ key: 'articleId', left: 'articleId', right: 'title'}"/>
jeepayPopupListSelect.value.open().then((selected) => {
console.log(selected);
jeepayPopupListSelect.value.close() //
})
@author terrfly
@site https://www.jeequan.com
@date 2022/11/26 16:24
-->
<template>
<uni-popup ref="popupRef" type="bottom" @maskClick="close" @change="change" mask-background-color="rgba(0,0,0,.5)">
<view class="card-wrapper">
<view class="selected-title" v-if="title">
{{ title }}
</view>
<view v-if="props.searchInputName" class="input-search">
<uni-easyinput
v-model="vdata.searchData[props.searchInputName]"
prefixIcon="search"
:inputBorder="false"
:clearable="false"
:styles="{
backgroundColor: 'transparent'
}"
type="text"
placeholder="搜索"
placeholderStyle=" color: rgba(0,0,0,0.85);font-size: 30rpx;"
/>
<view class="search-button" @tap="searchFunc">搜索</view>
</view>
<!-- 数据渲染 -->
<JTableList ref="jeepayTableListRef" :reqTableDataFunc="reqTableDataFuncWrapper" :searchData="vdata.searchData" :initData="false" height="406rpx">
<template #tableBody="{ record }">
<view class="store" @tap="selectFunc(record)">
<template v-if="isCheckbox">
<view class="more-selected" :class="{ 'more-disabled': record.hasDirector, 'more-active': hasSelected(record) }">
<image :src="record.hasDirector ? '/static/iconImg/icon-disable.svg' : '/static/iconImg/icon-check.svg'" mode="scaleToFill" />
</view>
</template>
<view v-else :class="{ 'store-dot-def': true, 'active-dot': hasSelected(record) }"></view>
<slot name="content" :record="record">
<view class="store-inner-slot">
<view class="left">
<text>{{ record[props.fields.left] }}</text>
</view>
<view class="right">{{ record[props.fields.right] }}</view>
</view>
</slot>
</view>
</template>
</JTableList>
<!-- <button v-if="vdata.hasNext" @tap="jeepayTableListRef.addNext()">下一页</button> -->
<view class="footer-wrapper">
<view class="footer-main">
<view class="footer-button">
<view class="flex-center" hover-class="touch-button" @tap="close">取消</view>
<view @tap="confirmFunc" class="confirm flex-center" hover-class="touch-button">确认</view>
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { inject, nextTick, reactive, ref, render, watch } from 'vue';
const jeepayTableListRef = ref();
//
const props = defineProps({
configMode: { type: String, default: '' }, //
//
reqTableDataFunc: { type: Function, default: () => {} },
// name
searchInputName: { type: String },
// ,
fields: { type: Object, default: { key: 'id', left: 'left', right: 'right' } },
//
isCheckbox: { type: Boolean, default: false },
//
title: [String, Number]
});
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc');
const emits = defineEmits(['confirm']);
const popupRef = ref();
console.log(props, 'propsprops');
const vdata = reactive({
searchData: {
}, //
hasNext: false, //
selectedList: [], //
promiseObject: {}
});
//
function searchFunc() {
jeepayTableListRef.value.refTable(true);
}
/** reqTableDataFunc 处理函数 */
function reqTableDataFuncWrapper(params) {
return props.reqTableDataFunc(params).then(({ bizData }) => {
vdata.hasNext = bizData.hasNext; //
return Promise.resolve({ bizData });
});
}
//
function hasSelected(record) {
return vdata.selectedList.filter((r) => r[props.fields.key] == record[props.fields.key]).length > 0;
}
/** 选择函数 **/
function selectFunc(record) {
//
if (hasSelected(record)) {
//
if (props.isCheckbox) {
vdata.selectedList.splice(
vdata.selectedList.findIndex((r) => r[props.fields.key] == record[props.fields.key]),
1
);
}
//
return false;
}
//
if (props.isCheckbox) {
if (record.hasDirector) return; //
return vdata.selectedList.push(record);
} else {
//
return (vdata.selectedList = [record]);
}
}
//
function confirmFunc() {
//
if (props.isCheckbox) {
emits('confirm', vdata.selectedList);
return vdata.promiseObject.resolve(vdata.selectedList);
}
//
emits('confirm', vdata.selectedList.length > 0 ? vdata.selectedList[0] : null);
vdata.promiseObject.resolve(vdata.selectedList.length > 0 ? vdata.selectedList[0] : null);
}
// , promise
// promise.then(selected)
// : Promise 使@confirm
// 使.then()
function open(defaultVal) {
console.log(111111111111111);
//
vdata.selectedList = [];
vdata.searchData[props.searchInputName] = '';
//
if (defaultVal) {
if (Array.isArray(defaultVal)) {
vdata.selectedList = defaultVal;
} else {
vdata.selectedList = [defaultVal];
}
}
popupRef.value.open();
nextTick(() => {
jeepayTableListRef.value.refTable(true);
uni.hideTabBar(); // nextTick
});
return new Promise((resolve, reject) => {
vdata.promiseObject.resolve = resolve;
vdata.promiseObject.reject = reject;
});
}
//
function close() {
popupRef.value.close();
uni.showTabBar();
}
const change = (e) => {
if (changePageMetaOverflowFunc) {
changePageMetaOverflowFunc(!e.show);
}
};
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open, close });
</script>
<style lang="scss" scoped>
.card-wrapper {
border-radius: 32rpx 32rpx 0 0;
background-color: #fff;
overflow: hidden;
min-height: 70vh;
max-height: 80vh;
overflow-y: auto;
.selected-title {
height: 110rpx;
line-height: 110rpx;
text-align: center;
font-size: 30rpx;
font-weight: 500;
border-bottom: 1rpx solid #ededed;
}
.input-search {
display: flex;
align-items: center;
padding-left: 10rpx;
margin: 30rpx;
border-radius: 10rpx;
background-color: #f7f7f7;
.search-button {
padding: 24rpx 30rpx;
font-size: 32rpx;
font-weight: 500;
color: #2980fd;
}
}
.store {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 40rpx;
height: 120rpx;
font-size: 30rpx;
.more-selected {
width: 36rpx;
height: 36rpx;
border-radius: 6rpx;
margin-right: 20rpx;
border: 2rpx solid rgba(217, 217, 217, 1);
image {
width: 100%;
height: 100%;
}
}
.more-disabled {
background-color: #f7f7f7;
}
.more-active {
background-color: #2980fd;
}
.store-dot-def {
position: relative;
margin-right: 20rpx;
width: 36rpx;
height: 36rpx;
background-color: #d7d8d9;
border-radius: 50%;
&::after {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
}
}
.active-dot {
background-color: #2980fd;
}
.store-inner-slot {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
.left {
display: flex;
align-items: center;
}
.right {
color: #999999;
}
}
}
.all-store::after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 40rpx;
right: 40rpx;
height: 1rpx;
background-color: #ededed;
}
.footer-wrapper {
height: 186rpx;
.footer-main {
position: fixed;
left: 0;
right: 0;
bottom: env(safe-area-inset-bottom);
border-top: 1rpx solid #ededed;
.tips {
margin: 20rpx;
text-align: center;
font-size: 27rpx;
color: #a6a6a6;
}
.footer-button {
padding: 0 30rpx;
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
justify-content: space-between;
view {
width: 330rpx;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
background-color: #f7f7f7;
}
.confirm {
color: #fff;
background: $jeepay-bg-primary;
}
}
}
}
}
</style>

View File

@ -1,387 +0,0 @@
<!--
组件作用 弹层 列表支持 单选 多选
使用方法
<JeepayPopupListSelect ref="jeepayPopupListSelect" :reqTableDataFunc="reqTableDataFunc" :fields="{ key: 'articleId', left: 'articleId', right: 'title'}"/>
jeepayPopupListSelect.value.open().then((selected) => {
console.log(selected);
jeepayPopupListSelect.value.close() //
})
@author terrfly
@site https://www.jeequan.com
@date 2022/11/26 16:24
-->
<template>
<uni-popup ref="popupRef" type="bottom" @maskClick="close" @change="change" mask-background-color="rgba(0,0,0,.5)" :safe-area="false">
<view class="card-wrapper">
<view class="selected-title" v-if="title">
{{ title }}
</view>
<view class="search-wrap" v-if="props.searchInputName">
<view class="input-search">
<uni-easyinput
v-model="vdata.searchData[props.searchInputName]"
prefixIcon="search"
:inputBorder="false"
:clearable="false"
:styles="{
backgroundColor: 'transparent'
}"
type="text"
placeholder="搜索"
placeholderStyle=" color: rgba(0,0,0,0.85);font-size: 30rpx;"
/>
<view class="search-button" @tap="searchFunc">搜索</view>
</view>
<!-- <view class="add-btn" hover-class="touch-button" v-if="props.addUse" @tap="">新增应用</view> -->
</view>
<!-- 数据渲染 -->
<JTableList ref="jeepayTableListRef" :reqTableDataFunc="reqTableDataFuncWrapper" :searchData="vdata.searchData" :initData="false" height="406rpx">
<template #tableBody="{ record }">
<view class="store" @tap="selectFunc(record)">
<template v-if="isCheckbox">
<view class="more-selected" :class="{ 'more-disabled': record.hasDirector, 'more-active': hasSelected(record) }">
<image :src="record.hasDirector ? '/static/iconImg/icon-disable.svg' : '/static/iconImg/icon-check.svg'" mode="scaleToFill" />
</view>
</template>
<view v-else :class="{ 'store-dot-def': true, 'active-dot': hasSelected(record) }"></view>
<slot name="content" :record="record">
<view class="store-inner-slot">
<view class="left">
<!-- <text>{{ record[props.fields.left] }}</text> -->
<text class="tit">{{ record[props.fields.left] }}</text>
<text class="ino" v-if="record.intro">{{ record.intro }}</text>
</view>
<view class="right">{{ record[props.fields.right] }}</view>
</view>
</slot>
</view>
</template>
</JTableList>
<!-- <button v-if="vdata.hasNext" @tap="jeepayTableListRef.addNext()">下一页</button> -->
<view class="footer-wrapper">
<view class="footer-main">
<view class="footer-button">
<view class="flex-center" hover-class="touch-button" @tap="close">取消</view>
<view @tap="confirmFunc" class="confirm flex-center" hover-class="touch-button">确认</view>
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { inject, nextTick, reactive, ref, render, watch } from 'vue';
const jeepayTableListRef = ref();
//
const props = defineProps({
configMode: { type: String, default: '' }, //
//
reqTableDataFunc: { type: Function, default: () => {} },
// name
searchInputName: { type: String },
// ,
fields: { type: Object, default: { key: 'id', left: 'left', right: 'right' } },
//
isCheckbox: { type: Boolean, default: false },
//
title: [String, Number],
//
addUse: { type: Boolean, default: false }
});
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc');
const emits = defineEmits(['confirm']);
const popupRef = ref();
console.log(props, 'propsprops');
const vdata = reactive({
searchData: {}, //
hasNext: false, //
selectedList: [], //
promiseObject: {}
});
//
function searchFunc() {
jeepayTableListRef.value.refTable(true);
}
/** reqTableDataFunc 处理函数 */
function reqTableDataFuncWrapper(params) {
return props.reqTableDataFunc(params).then(({ bizData }) => {
vdata.hasNext = bizData.hasNext; //
return Promise.resolve({ bizData });
});
}
//
function hasSelected(record) {
return vdata.selectedList.filter((r) => r[props.fields.key] == record[props.fields.key]).length > 0;
}
/** 选择函数 **/
function selectFunc(record) {
//
if (hasSelected(record)) {
//
if (props.isCheckbox) {
vdata.selectedList.splice(
vdata.selectedList.findIndex((r) => r[props.fields.key] == record[props.fields.key]),
1
);
}
//
return false;
}
//
if (props.isCheckbox) {
if (record.hasDirector) return; //
return vdata.selectedList.push(record);
} else {
//
return (vdata.selectedList = [record]);
}
}
//
function confirmFunc() {
//
if (props.isCheckbox) {
emits('confirm', vdata.selectedList);
return vdata.promiseObject.resolve(vdata.selectedList);
}
//
emits('confirm', vdata.selectedList.length > 0 ? vdata.selectedList[0] : null);
vdata.promiseObject.resolve(vdata.selectedList.length > 0 ? vdata.selectedList[0] : null);
}
// , promise
// promise.then(selected)
// : Promise 使@confirm
// 使.then()
function open(defaultVal) {
//
vdata.selectedList = [];
vdata.searchData[props.searchInputName] = '';
//
if (defaultVal) {
if (Array.isArray(defaultVal)) {
vdata.selectedList = defaultVal;
} else {
vdata.selectedList = [defaultVal];
}
}
popupRef.value.open();
nextTick(() => {
jeepayTableListRef.value.refTable(true);
uni.hideTabBar(); // nextTick
});
return new Promise((resolve, reject) => {
vdata.promiseObject.resolve = resolve;
vdata.promiseObject.reject = reject;
});
}
//
function close() {
popupRef.value.close();
uni.showTabBar();
}
const change = (e) => {
if (changePageMetaOverflowFunc) {
changePageMetaOverflowFunc(!e.show);
}
};
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open, close });
</script>
<style lang="scss" scoped>
.card-wrapper {
border-radius: 32rpx 32rpx 0 0;
background-color: #fff;
overflow: hidden;
min-height: 70vh;
max-height: 80vh;
overflow-y: auto;
.selected-title {
height: 110rpx;
line-height: 110rpx;
text-align: center;
font-size: 30rpx;
font-weight: 500;
border-bottom: 1rpx solid #ededed;
}
.search-wrap {
padding: 30rpx;
display: flex;
.input-search {
flex: 1;
display: flex;
align-items: center;
padding-left: 10rpx;
border-radius: 10rpx;
background-color: #f7f7f7;
.search-button {
padding: 24rpx 30rpx;
font-size: 32rpx;
font-weight: 500;
color: #2980fd;
}
}
.add-btn {
border-radius: 10rpx;
color: #fff;
padding: 0 20upx;
display: flex;
align-items: center;
justify-content: center;
background: $jeepay-bg-primary;
margin-left: 30rpx;
}
}
.store {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
margin: 40rpx;
font-size: 30rpx;
background-color: #f5f5f5;
padding: 20rpx;
border-radius: 12rpx;
.more-selected {
flex-shrink: 0;
width: 36rpx;
height: 36rpx;
border-radius: 6rpx;
margin-right: 20rpx;
border: 2rpx solid rgba(217, 217, 217, 1);
image {
width: 100%;
height: 100%;
}
}
.more-disabled {
background-color: #f7f7f7;
}
.more-active {
background-color: #2980fd;
}
.store-dot-def {
position: relative;
margin-right: 20rpx;
width: 36rpx;
height: 36rpx;
background-color: #d7d8d9;
border-radius: 50%;
&::after {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
}
}
.active-dot {
background-color: #2980fd;
}
.store-inner-slot {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
.left {
display: flex;
flex-direction: column;
.ino {
color: #999;
padding-top: 12upx;
font-size: 24upx;
}
}
.right {
color: #999999;
}
}
}
.all-store::after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 40rpx;
right: 40rpx;
height: 1rpx;
background-color: #ededed;
}
.footer-wrapper {
height: 186rpx;
.footer-main {
position: fixed;
left: 0;
right: 0;
bottom: env(safe-area-inset-bottom);
border-top: 1rpx solid #ededed;
background-color: #fff;
.tips {
margin: 20rpx;
text-align: center;
font-size: 27rpx;
color: #a6a6a6;
}
.footer-button {
padding: 0 30rpx;
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
justify-content: space-between;
view {
width: 330rpx;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
background-color: #f7f7f7;
}
.confirm {
color: #fff;
background: $jeepay-bg-primary;
}
}
}
}
}
</style>

View File

@ -1,116 +0,0 @@
<!--
单选 view 一般用作 form表单内使用
@author terrfly
@site https://www.jeepay.vip
@date 2022/12/01 16:18
-->
<template>
<view>
<view @tap="show">
<!-- 插槽自定义内容 -->
<slot name="view" :record="vdata.checkedData">
<view class="selected-radio">
<view v-if="hasVal()" style="color: black">{{vdata.checkedData?.label}}</view>
<view v-else>{{props.label}}</view>
<image style="width: 30rpx;height: 30rpx" src="/static/right.svg" mode="scaleToFill" />
</view>
</slot>
</view>
<!-- popup tap不能放置在同一个 view下 -->
<view>
<JSinglePopup ref="popupRef" :list="props.list" @confirm="confirmFunc" />
</view>
</view>
</template>
<script setup>
import { ref, reactive, nextTick, watch, onMounted, inject } from "vue"
const popupRef = ref()
// emit 使 v-model:value="val"
const emits = defineEmits(['update:value', 'change'])
const props = defineProps({
//
value: { type: [String, Number] },
//
label: { type: [String, Number], default: "请选择" },
//
list: { type: Array, default: () => [] },
//
isCheckbox: { type: Boolean, default: false },
})
console.log(props.isCheckbox,'isCheckboxisCheckboxisCheckboxisCheckbox');
onMounted(()=>{
changePropsVal(props.value)
})
//
watch(() => props.value, (newVal, oldVal) => {
changePropsVal(newVal)
}
)
function changePropsVal(newVal){
let list = props.list.filter(r => r.value == newVal)
vdata.checkedData = list.length > 0 ? list[0] : { }
}
const vdata = reactive({
checkedData: { } //
})
function show(){
popupRef.value.open(vdata.checkedData.value)
}
//
function confirmFunc(v){
vdata.checkedData = v
emits("update:value", v.value)
if(v.value!==1){
emits("change", v.value)
}
}
function hasVal(){
return vdata.checkedData && vdata.checkedData.label ? true : false
}
</script>
<style lang="scss" scoped>
.selected-radio {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 32rpx;
color: #b3b3b3;
image {
width: 120rpx;
height: 120rpx;
}
}
</style>

View File

@ -1,134 +0,0 @@
<!--
Jeepay 门店选择 / 应用选择
@author terrfly
@site https://www.jeequan.com
@date 2022/12/06 12:55
-->
<template>
<!-- 选择门店 -->
<JeepayPopupListSelect
ref="jeepayRedPopupListSelectByBizinfos"
:reqTableDataFunc="reqTableDataByBizsFunc"
:searchInputName="getSearchInputName()"
:fields="getField()"
/>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { reqLoad, API_URL_MCH_STORE_LIST, API_URL_MCH_APP_LIST } from '@/http/apiManager.js'
//
const props = defineProps({
configMode: { type: String, default: ''}, //
//
isCheckbox: { type: Boolean, default: false },
//
autoClose: { type: Boolean, default: true },
//
bizType: { type: String, default: 'store' },
//
isShowAllBiz: { type: Boolean, default: false },
//
params:{type:Object,default:()=>({})}
})
const jeepayRedPopupListSelectByBizinfos = ref()
function getField(){
if(props.bizType == 'store'){
return { key: 'storeId', left: 'storeName', right: 'storeId' }
}
if(props.bizType == 'mchApp'){
return { key: 'appId', left: 'appName', right: 'appId' }
}
}
function getSearchInputName(){
if(props.bizType == 'store'){
return "storeName"
}
if(props.bizType == 'mchApp'){
return "appName"
}
}
function reqTableDataByBizsFunc(params) {
Object.assign(params,props.params)
console.log(params);
let apiResult = null;
if(props.bizType == 'store'){
apiResult = reqLoad.list(API_URL_MCH_STORE_LIST, params)
}
if(props.bizType == 'mchApp'){
apiResult = reqLoad.list(API_URL_MCH_APP_LIST, params)
}
return apiResult.then((apiRes) => {
return processApiResBizData(params, apiRes)
})
}
//
function open (defaultVal){
console.log(defaultVal,'defaultValdefaultVal')
return jeepayRedPopupListSelectByBizinfos.value.open(defaultVal).then((selected) => {
//
if(props.autoClose){
close()
}
return selected;
})
}
function close(){
jeepayRedPopupListSelectByBizinfos.value.close() //
}
function processApiResBizData(params, apiRes){
// (index = 0 )
if(params.pageNumber == 1 && props.isShowAllBiz){
if(props.bizType == 'store'){
apiRes.bizData.records.unshift({storeName: '全部门店', storeId: ''})
}
if(props.bizType == 'mchApp'){
apiRes.bizData.records.unshift({appName: '全部应用', appId: ''})
}
}
return apiRes
}
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open, close })
</script>
<style>
</style>

View File

@ -1,355 +0,0 @@
<!--
组件作用 弹层 列表支持 单选 多选
使用方法
<JeepayPopupListSelect ref="jeepayPopupListSelect" :reqTableDataFunc="reqTableDataFunc" :fields="{ key: 'articleId', left: 'articleId', right: 'title'}"/>
jeepayPopupListSelect.value.open().then((selected) => {
console.log(selected);
jeepayPopupListSelect.value.close() //
})
@author terrfly
@site https://www.jeequan.com
@date 2022/11/26 16:24
-->
<template>
<uni-popup ref="popupRef" type="bottom" @maskClick="close" @change="change" mask-background-color="rgba(0,0,0,.5)" :safe-area="false">
<view class="card-wrapper">
<view class="selected-title" v-if="title">
{{ title }}
</view>
<view v-if="props.searchInputName" class="input-search">
<uni-easyinput
v-model="vdata.searchData[props.searchInputName]"
prefixIcon="search"
:inputBorder="false"
:clearable="false"
:styles="{
backgroundColor: 'transparent',
}"
type="text"
placeholder="搜索"
placeholderStyle=" color: rgba(0,0,0,0.85);font-size: 30rpx;"
/>
<view class="search-button" @tap="searchFunc">搜索</view>
</view>
<!-- 数据渲染 -->
<JTableList ref="jeepayTableListRef" :reqTableDataFunc="reqTableDataFuncWrapper" :searchData="vdata.searchData" :initData="false" height='406rpx'>
<template #tableBody="{ record }">
<view class="store" @tap="selectFunc(record)">
<template v-if="isCheckbox">
<view class="more-selected" :class="{ 'more-disabled': record.hasDirector, 'more-active': hasSelected(record) }">
<image :src="record.hasDirector ? '/static/iconImg/icon-disable.svg' : '/static/iconImg/icon-check.svg'" mode="scaleToFill" />
</view>
</template>
<view v-else :class="{ 'store-dot-def': true, 'active-dot': hasSelected(record) }"></view>
<slot name="content" :record="record">
<view class="store-inner-slot">
<view class="left">
<text>{{ record[props.fields.left] }}</text>
</view>
<view class="right">{{ record[props.fields.right] }}</view>
</view>
</slot>
</view>
</template>
</JTableList>
<!-- <button v-if="vdata.hasNext" @tap="jeepayTableListRef.addNext()">下一页</button> -->
<view class="footer-wrapper">
<view class="footer-main">
<view class="footer-button">
<view class="flex-center" hover-class="touch-button" @tap="close">取消</view>
<view @tap="confirmFunc" class="confirm flex-center" hover-class="touch-button">确认</view>
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { inject, nextTick, reactive, ref, render, watch } from 'vue'
const jeepayTableListRef = ref()
//
const props = defineProps({
//
reqTableDataFunc: { type: Function, default: () => {} },
// name
searchInputName: { type: String },
// ,
fields: { type: Object, default: { key: 'id', left: 'left', right: 'right' } },
//
isCheckbox: { type: Boolean, default: false },
//
title: [String, Number],
})
let changePageMetaOverflowFunc = inject('changePageMetaOverflowFunc')
const emits = defineEmits(['confirm'])
const popupRef = ref()
const vdata = reactive({
searchData: {}, //
hasNext: false, //
selectedList: [], //
promiseObject: {},
})
//
function searchFunc() {
jeepayTableListRef.value.refTable(true)
}
/** reqTableDataFunc 处理函数 */
function reqTableDataFuncWrapper(params) {
return props.reqTableDataFunc(params).then(({ bizData }) => {
vdata.hasNext = bizData.hasNext //
return Promise.resolve({ bizData })
})
}
//
function hasSelected(record) {
return vdata.selectedList.filter((r) => r[props.fields.key] == record[props.fields.key]).length > 0
}
/** 选择函数 **/
function selectFunc(record) {
//
if (hasSelected(record)) {
//
if (props.isCheckbox) {
vdata.selectedList.splice(
vdata.selectedList.findIndex((r) => r[props.fields.key] == record[props.fields.key]),
1
)
}
//
return false
}
//
if (props.isCheckbox) {
if (record.hasDirector) return //
return vdata.selectedList.push(record)
} else {
//
return (vdata.selectedList = [record])
}
}
//
function confirmFunc() {
//
if (props.isCheckbox) {
emits('confirm', vdata.selectedList)
return vdata.promiseObject.resolve(vdata.selectedList)
}
//
emits('confirm', vdata.selectedList.length > 0 ? vdata.selectedList[0] : null)
vdata.promiseObject.resolve(vdata.selectedList.length > 0 ? vdata.selectedList[0] : null)
}
// , promise
// promise.then(selected)
// : Promise 使@confirm
// 使.then()
function open(defaultVal) {
//
vdata.selectedList = []
vdata.searchData[props.searchInputName] = ''
//
if (defaultVal) {
if (Array.isArray(defaultVal)) {
vdata.selectedList = defaultVal
} else {
vdata.selectedList = [defaultVal]
}
}
popupRef.value.open()
nextTick(() => {
jeepayTableListRef.value.refTable(true)
uni.hideTabBar() // nextTick
})
return new Promise((resolve, reject) => {
vdata.promiseObject.resolve = resolve
vdata.promiseObject.reject = reject
})
}
//
function close() {
popupRef.value.close()
uni.showTabBar()
}
const change = (e) => {
if (changePageMetaOverflowFunc) {
changePageMetaOverflowFunc(!e.show)
}
}
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ open, close })
</script>
<style lang="scss" scoped>
.card-wrapper {
border-radius: 32rpx 32rpx 0 0;
background-color: #fff;
overflow: hidden;
min-height: 70vh;
max-height: 80vh;
overflow-y: auto;
.selected-title {
height: 110rpx;
line-height: 110rpx;
text-align: center;
font-size: 30rpx;
font-weight: 500;
border-bottom: 1rpx solid #ededed;
}
.input-search {
display: flex;
align-items: center;
padding-left: 10rpx;
margin: 30rpx;
border-radius: 10rpx;
background-color: #f7f7f7;
.search-button {
padding: 24rpx 30rpx;
font-size: 32rpx;
font-weight: 500;
color: #2980fd;
}
}
.store {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 40rpx;
height: 120rpx;
font-size: 30rpx;
.more-selected {
width: 36rpx;
height: 36rpx;
border-radius: 6rpx;
margin-right: 20rpx;
border: 2rpx solid rgba(217, 217, 217, 1);
image {
width: 100%;
height: 100%;
}
}
.more-disabled {
background-color: #f7f7f7;
}
.more-active {
background-color: #2980fd;
}
.store-dot-def {
position: relative;
margin-right: 20rpx;
width: 36rpx;
height: 36rpx;
background-color: #d7d8d9;
border-radius: 50%;
&::after {
content: '';
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #fff;
}
}
.active-dot {
background-color: #2980fd;
}
.store-inner-slot {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
.left {
display: flex;
align-items: center;
}
.right {
color: #999999;
}
}
}
.all-store::after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 40rpx;
right: 40rpx;
height: 1rpx;
background-color: #ededed;
}
.footer-wrapper {
height: 186rpx;
.footer-main {
position: fixed;
left: 0;
right: 0;
bottom: env(safe-area-inset-bottom);
border-top: 1rpx solid #ededed;
.tips {
margin: 20rpx;
text-align: center;
font-size: 27rpx;
color: #a6a6a6;
}
.footer-button {
padding: 0 30rpx;
margin-top: 30rpx;
padding-bottom: 30rpx;
display: flex;
justify-content: space-between;
view {
width: 330rpx;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
background-color: #f7f7f7;
}
.confirm {
color: #fff;
background: $jeepay-bg-primary;
}
}
}
}
}
</style>

View File

@ -1,74 +0,0 @@
<!--
组件作用 状态筛选器 一般用作搜索栏右侧
使用方法
@author terrfly
@site https://www.jeequan.com
@date 2022/11/26 16:24
-->
<template>
<view>
<view class="code-state" @tap="statePopup.open(props.bizType)">
{{ props.list.find(i => {
return i.value == props.bizType
}).label }}
<image src="/pageDevice/static/devIconImg/icon-arrow-down.svg" mode="scaleToFill" />
</view>
</view>
<view>
<JSinglePopup :list="props.list" :title="props.title" ref="statePopup" @confirm="confirmState" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const emits = defineEmits(['update:bizType', 'change'])
//
const props = defineProps({
//
bizType: { type: [Number, String] },
//
list: { type: Array },
title: { type: String }
})
const vdata = reactive({
selected: {} //
})
const statePopup = ref(null)
//
function confirmState(r){
vdata.selected = r || { }
emits('update:bizType', vdata.selected.value)
emits('change', vdata.selected)
}
</script>
<style lang="scss" scoped>
.code-state {
display: flex;
align-items: center;
margin-left: 40rpx;
font-size: 30rpx;
color: #222425;
image {
margin-left: 10rpx;
width: 40rpx;
height: 40rpx;
}
}
</style>

View File

@ -1,79 +0,0 @@
<!--
组件作用 状态筛选器 一般用作搜索栏右侧
使用方法
@author terrfly
@site https://www.jeequan.com
@date 2022/11/26 16:24
-->
<template>
<view>
<view class="code-state" @tap="statePopup.open(props.state)">
{{ vdata.selected.label || '全部状态' }}
<image src="/pageDevice/static/devIconImg/icon-arrow-down.svg" mode="scaleToFill" />
</view>
</view>
<view>
<JSinglePopup :list="stateList" title="按设备状态筛选" ref="statePopup" @confirm="confirmState" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const emits = defineEmits(['update:state', 'change'])
//
const props = defineProps({
//
state: { type: [Number, String] },
})
const vdata = reactive({
selected: {} , //
})
const statePopup = ref(null)
const stateList = reactive([
{ label: '全部状态', value: '' },
{ label: '启用', value: '1' },
{ label: '禁用', value: '0' },
])
//
function confirmState(r){
vdata.selected = r || { }
emits('update:state', vdata.selected.value)
emits('change', vdata.selected.value)
}
</script>
<style lang="scss" scoped>
.code-state {
display: flex;
align-items: center;
margin-left: 40rpx;
font-size: 30rpx;
color: #222425;
image {
margin-left: 10rpx;
width: 40rpx;
height: 40rpx;
}
}
</style>

View File

@ -1,119 +0,0 @@
<!--
Jeepay 通用状态切换按钮 支持switch和badge两个格式 根据权限进行判断
参考 jeepay-ui组件
@author terrfly
@site https://www.jeepay.vip
@date 2021/5/8 07:18
-->
<template>
<view>
<template v-if="props.showSwitchType" >
<switch v-if="vdata.isShowSwitchFlag" :checked="vdata.switchChecked" color="#238FFC" :style="{ transform: 'scale(' + scale + ')', margin: margin }" @change="changeFunc" />
</template>
<template v-else>
<image v-if="vdata.switchChecked == 1" class="default-image" src="/pageDevice/static/devIconImg/icon-default.svg" mode="scaleToFill" />
<image v-if="vdata.switchChecked == 0" class="default-image" src="/pageDevice/static/devIconImg/icon-noDefault.svg" mode="scaleToFill" />
</template>
</view>
<JeepayPopupConfirm ref="jeepayPopupConfirmRef" />
</template>
<script setup>
import { ref, reactive, nextTick, watch, onMounted } from "vue"
const props = defineProps({
//
scale: { type: Number, default: 0.8 }, // .8
margin: { type: String, default: "0" }, // 0
showSwitchType: { type: Boolean, default: false }, // badge
//, 0- 1-
state: { type: [Number,String], default: 1 },
//
confirm: { type: Boolean, default: true },
confirmTitle: { type: String, default: '确定修改状态?' }, //
// updateStateFunc. promise
updateStateFunc: { type: Function },
})
const jeepayPopupConfirmRef = ref() //
const emits = defineEmits(["update:state"])
onMounted(()=>{
vdata.switchChecked = props.state == 1
})
const vdata = reactive({
isShowSwitchFlag: true , //
switchChecked: true, //
})
// props
watch(() => props.state, function(o, n){
vdata.switchChecked = props.state == 1
}
)
function changeFunc(e){
let changeVal = e.detail.value
//
if(props.confirm){
jeepayPopupConfirmRef.value.open(props.confirmTitle).then(() => {
return propsUpdateStateFunc(changeVal ? 1 : 0)
}).then(() => {
emits("update:state", changeVal ? 1 : 0)
reloadSwitch(changeVal)
}).catch(() => {
reloadSwitch(!changeVal)
})
}else{ //
propsUpdateStateFunc(changeVal ? 1 : 0).then(() => {
emits("update:state", changeVal ? 1 : 0)
reloadSwitch(changeVal)
}).catch(() => {
reloadSwitch(!changeVal)
})
}
}
// uniapp-switch v-model:checked
function reloadSwitch(changeVal){
vdata.switchChecked = changeVal
vdata.isShowSwitchFlag = false
nextTick(() => vdata.isShowSwitchFlag = true)
}
// props. default app
// APP default : () => { return (state) => {Promie.resole()} } ( default )
function propsUpdateStateFunc(state){
if(props.updateStateFunc){
return props.updateStateFunc(state)
}
return Promise.resolve()
}
</script>
<style lang="scss" scoped>
.default-image {
width: 50rpx;
height: 50rpx;
}
</style>

View File

@ -1,119 +0,0 @@
<!--
Jeepay 表格列表 支持 下滑 上滑刷新
业务页面最好也监听下 触底函数 否则H5无法监听到
import { onReachBottom } from '@dcloudio/uni-app'
onReachBottom(() => { })
@author terrfly
@site https://www.jeequan.com
@date 2022/11/16 15:55
-->
<template>
<view>
<template v-for="(record, i) in vdata.allData" :key="i">
<slot name="tableBody" :record="record" :index="i" />
</template>
</view>
<view class="list-null" v-if="!vdata.apiResData.hasNext && showListNull">暂无更多数据</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app';
//
const props = defineProps({
reqTableDataFunc: { type: Function, default: () => {} },
searchData: { type: Object, default: () => {} }, //
pageSize: { type: Number, default: 10 }, //
initData: { type: Boolean, default: true }, // true
showListNull: { type: Boolean, default: true } //
});
const vdata = reactive({
allData: [], // appweb app
//
apiResData: { total: 0, records: [] },
//
iPage: { pageNumber: 1, pageSize: props.pageSize }
});
onMounted(() => {
//
props.initData ? refTable(true) : undefined;
});
//
function refTable(isToFirst = false) {
if (isToFirst) {
//
vdata.iPage.pageNumber = 1;
vdata.allData = []; //
}
//
return props.reqTableDataFunc(Object.assign({}, vdata.iPage, props.searchData)).then(({ bizData }) => {
Object.assign(vdata.apiResData, bizData); //
if (bizData.records) {
vdata.allData.push(...bizData.records); // forEach
}
});
}
/** 追加下一页数据 **/
function addNext() {
//
if (vdata.apiResData.hasNext) {
vdata.iPage.pageNumber++;
refTable(false);
}
}
//
onPullDownRefresh(() => {
refTable(true).then(() => {
uni.stopPullDownRefresh();
});
});
//
onReachBottom(() => {
addNext();
});
// https://www.jianshu.com/p/39d14c25c987
defineExpose({ refTable, addNext });
</script>
<style lang="scss" scoped>
.list-null {
position: relative;
line-height: 110rpx;
text-align: center;
font-size: 26rpx;
color: #a6a6a6;
&::after,
&::before {
content: '';
display: block;
position: absolute;
top: 50%;
width: 30%;
height: 2rpx;
background-color: #ededed;
transform: translateY(-50%);
}
&::after {
left: 40rpx;
}
&::before {
right: 40rpx;
}
}
</style>

View File

@ -1,90 +0,0 @@
<!--
Jeepay 通用列表条目 包含 头像 主标题 副标题
@author terrfly
@site https://www.jeequan.com
@date 2022/11/16 15:55
-->
<template>
<view :class="`list-item ${props.viewClass}`">
<image :style="props.logoStyle" v-if="props.logo" :src="props.logo" mode="scaleToFill" />
<view class="list-info">
<view class="list-title">
<view class="list-name">
<slot name="title">{{ props.title }} </slot>
</view>
<slot name="titleRight">
<!-- 直接写 typeof 页面报错 -->
<template v-if="isShowState()" >
<view v-if="props.state == 1" class="state-dot state-dot-enable"></view>
<view v-else class="state-dot state-dot-disable"></view>
</template>
<template v-if="navListComputed">
<image style="width: 70rpx; height: 70rpx" src="/pageDevice/static/devIconImg/icon-more-white.svg" mode="scaleToFill" @tap="single.open()" />
</template>
</slot>
</view>
<view class="list-subtitle"><slot name="subtitle">{{ props.subtitle }} </slot></view>
</view>
<JSinglePopup ref="single" :list="navListComputed" activeColor="#FF5B4C" />
</view>
</template>
<script setup>
import {ref, reactive, onMounted, computed } from 'vue'
import ak from '@/commons/utils/ak.js'
//
const single = ref()
//
const props = defineProps({
title: { type: [String, Number] }, //
subtitle: { type: [String, Number] }, //
logo: { type: String }, //
logoStyle: { type: Object } , // logo
moreBtnList: { type: Array }, //
// or state moreBtnList 使 titleRight
state: { type: [Number, String] },
viewClass: { type: String, default: '' }, // class(),
})
function isShowState(){
return typeof(props.state) != 'undefined'
}
//
let navListComputed = computed(() => {
if(!props.moreBtnList){
return props.moreBtnList
}
return props.moreBtnList.filter(r => hasEnt(r.entId))
})
function hasEnt(entId){
//
if(!entId){
return true
}
return ak.ent.has(entId)
}
</script>
<style>
</style>

View File

@ -1,56 +0,0 @@
<template>
<view class="tag-wrapper" :class="[calcType()]" :style="styles">
<slot />
</view>
</template>
<script setup>
import { reactive } from 'vue'
const props = defineProps({
type: { type: [String, Object], default: 'green' },
styles: { type: Object, default: () => ({}) },
})
const classList = ['purple', 'green', 'blue', 'green-rgba']
const calcType = () => {
try {
//
if (Object.keys(props.styles).length > 0) return ''
// 使
if (classList.includes(props.type)) return props.type
throw `预设样式类型中未包含此字段 请使使用style字段传入样式对象 自定义样式 注意样式名驼峰语法 目前预设样式字段有 ${classList.join(',')} `
} catch (err) {
console.error('error', err)
}
}
</script>
<style lang="scss" scoped>
.tag-wrapper {
display: inline-block;
margin-left: 15rpx;
padding: 0 15rpx;
height: 40rpx;
line-height: 40rpx;
border-radius: 6rpx;
text-align: center;
font-size: 23rpx;
color: #fff;
}
.purple {
background: linear-gradient(270deg, rgba(220, 61, 138, 1) 0%, rgba(187, 23, 92, 1) 100%);
}
.green {
background: linear-gradient(270deg, rgba(61, 220, 68, 1) 0%, rgba(23, 187, 118, 1) 100%);
}
.blue {
background: linear-gradient(270deg, rgba(35, 161, 252, 1) 0%, rgba(26, 102, 255, 1) 100%);
}
.green-rgba{
color: rgba(23, 188, 118, 1);
background: linear-gradient(270deg, rgba(61, 220, 68, 0.3) 0%, rgba(23, 187, 118, 0.3) 100%);
}
</style>

View File

@ -1,167 +0,0 @@
<!--
图片上传组件
@author terrfly
@site https://www.jeequan.com
@date 2022/11/30 18:18
-->
<template>
<view style="flex-grow: 1">
<!-- 图片内 x 号的模式 -->
<template v-if="props.mode == 'img'">
<!-- 包含图片 -->
<template v-if="props.src">
<view class="image-wrapper">
<image v-if="!props.readonly" @tap="delImg" class="del-image" src="/static/iconImg/icon-x-white.svg" mode="scaleToFill" />
<image class="default-img" :src="props.src" @tap="preview"></image>
</view>
</template>
<template v-else>
<!-- 不包含图片 -->
<view @tap="chooseImageAndUpload" style="flex-grow: 1; display: flex; justify-content: space-between; align-items: center">
<image
v-if="!props.readonly"
style="width: 150rpx; height: 150rpx; background-color: #f7f7f7; border-radius: 15rpx"
src="/static/iconImg/default-img.svg"
mode="scaleToFill"
/>
<image src="/pageDevice/static/devIconImg/icon-arrow-sex.svg" mode="scaleToFill" style="width: 120rpx; height: 120rpx" />
</view>
</template>
</template>
<!-- 页面图片 加入 切换按钮 -->
<template v-if="props.mode == 'viewbtn'">
<image class="default-img" :src="props.src" @tap="preview" mode="aspectFill"></image>
<!-- 图片预览手写非原生 -->
<enlarge v-if="vdata.showEnlarge" :imgs="props.src" :changeIsShow="!props.readonly" @chooseImg="chooseImageAndUpload" @enlargeClose="vdata.showEnlarge = false" />
</template>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import http from '@/http/http.js';
import infoBox from '@/commons/utils/infoBox.js';
import enlarge from './enlarge.vue'; //
import { API_URL_SINGLE_FILE_UPLOAD, $ossFilesForm } from '@/http/apiManager.js';
// emit 使 v-model:src="val"
const emit = defineEmits(['update:src', 'change']);
//
const props = defineProps({
src: { type: String, default: '' }, //
bizType: { type: String, default: '' }, //
imgSize: { type: Number, default: 5 }, // 5 M
// img - viewbtn-
mode: { type: String, default: 'img' },
//
readonly: { type: Boolean, default: false }
});
//
const vdata = reactive({
showEnlarge: false,
action: '', // form
uploadForm: {
action: '', //
header: {}, //
params: {} //
}
});
//
function preview() {
if (props.mode == 'img') {
//
uni.previewImage({ urls: [props.src] });
} else {
//
vdata.showEnlarge = true;
}
}
//
function delImg() {
emit('update:src', '');
emit('change', '');
}
// and
function chooseImageAndUpload() {
// && &&
uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'] }).then((res) => {
let file = res.tempFiles[0];
//
if (!beforeCheck(file)) {
return false;
}
//
$ossFilesForm(props.bizType, file).then(({ bizData }) => {
//
if (bizData.formActionUrl === 'LOCAL_SINGLE_FILE_URL') {
return http.upload(API_URL_SINGLE_FILE_UPLOAD, { bizType: props.bizType }, file).then(({ bizData }) => {
emit('update:src', bizData);
emit('change', bizData);
});
}
// oss
uni.uploadFile({ url: bizData.formActionUrl, filePath: file.path, name: 'file', formData: bizData.formParams }).then((ossRes) => {
if (ossRes.statusCode == 200) {
//
emit('update:src', bizData.ossFileUrl);
emit('change', bizData.ossFileUrl);
return false;
}
infoBox.showToast('oss服务响应异常');
});
});
});
}
function beforeCheck(file) {
return true;
}
defineExpose({
preview
});
</script>
<style lang="scss" scoped>
.default-img {
display: block;
width: 150rpx;
height: 150rpx;
background-color: #f7f7f7;
border-radius: 15rpx;
}
.image-wrapper {
position: relative;
width: 150rpx;
height: 150rpx;
margin-bottom: 20upx;
.del-image {
position: absolute;
top: -20rpx;
right: -20rpx;
z-index: 10;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background-color: tomato;
}
}
</style>

View File

@ -1,143 +0,0 @@
<template>
<view class="previewImage" :style="{ 'background-color': 'rgba(0,0,0,' + opacity + ')' }" @tap.stop="close">
<movable-area class="marea" scale-area>
<movable-view
:id="'movable-view-' + i"
:key="'movable-view-' + i"
class="mview"
direction="all"
:out-of-bounds="false"
:inertia="true"
damping="90"
friction="2"
scale="true"
scale-min="1"
scale-max="4"
:scale-value="scale"
>
<image
:id="'image-' + i"
:key="'movable-view' + i"
class="image"
:src="imgs"
:data-index="i"
:data-src="img"
mode="widthFix"
/>
</movable-view>
</movable-area>
<view v-if="changeIsShow" class="change-img" @click="chooseImg">更换图片</view>
</view>
</template>
<script>
export default {
name: "ksj-previewImage", //
props: {
imgs: {
//
type: String,
required: true,
default: "",
},
//,01
opacity: {
type: Number,
default: 1,
},
changeIsShow: { type: Boolean, default: true },
},
data() {
return {
swiper: false, //
show: false, //
index: 0, //
deg: 0, //
time: 0, //
interval: 1000, //
scale: 1, //
}
},
methods: {
chooseImg() {
this.$emit("chooseImg")
},
//
rotate(e) {
this.deg = this.deg == 270 ? 0 : this.deg + 90
},
close() {
this.$emit("enlargeClose")
},
},
}
</script>
<!--使用scss,只在本组件生效-->
<style lang="scss" scoped>
.previewImage {
z-index: 25;
position: fixed;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height: 100%;
background-color: #000000;
user-select: none;
.marea {
height: 100%;
width: 100%;
position: fixed;
overflow: hidden;
.mview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: auto;
min-height: 100%;
.image {
width: 100%;
}
}
}
.rotate {
position: absolute;
right: 10rpx;
width: 120rpx;
height: 56rpx;
bottom: 10rpx;
text-align: center;
padding: 10rpx;
.text {
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 30rpx;
border-radius: 20rpx;
border: 1rpx solid #f1f1f1;
padding: 6rpx 22rpx;
user-select: none;
}
.text:active {
background-color: rgba(100, 100, 100, 0.5);
}
}
}
.change-img {
position: fixed;
width: 300rpx;
bottom: 5%;
left: 50%;
margin-left: -150rpx;
text-align: center;
z-index: 30;
color: #fff;
padding: 30rpx;
box-sizing: border-box;
background-color: #0041c4;
border-radius: 10rpx;
}
</style>

View File

@ -1,135 +0,0 @@
<template>
<view v-show="isShow">
<view class="shade" @tap="hide"></view>
<view class="pop">
<view class="flex_col" style="margin-bottom: 20rpx;">
<view class="preview" :style="{'backgroundColor':pickerColor}"></view>
<view class="value">
<text v-if="pickerColor">颜色值{{pickerColor}}</text>
</view>
<view class="ok" @tap="setColor">确定</view>
</view>
<view class="list flex_col" v-for="(item,index) in colorArr" :key="index">
<view v-for="(v,i) in item" :key="i"
:style="{'backgroundColor':v}"
:data-color="v"
:data-index="index"
:data-i="i"
:class="{'active':(index==pickerArr[0] && i==pickerArr[1])}"
@tap="picker"></view>
</view>
<view :style="{'height':(bottom+'px')}"></view>
</view>
</view>
</template>
<script>
export default {
name:'picker-color',
props:{
isShow: {
type: Boolean,
default: false,
},
bottom:{
type: Number,
default: 0,
}
},
data() {
return {
colorArr:[
['#000000','#111111','#222222','#333333','#444444','#666666','#999999','#CCCCCC','#EEEEEE','#FFFFFF'],
['#ff0000','#ff0033','#ff3399','#ff33cc','#cc00ff','#9900ff','#cc00cc','#cc0099','#cc3399','#cc0066'],
['#cc3300','#cc6600','#ff9933','#ff9966','#ff9999','#ff99cc','#ff99ff','#cc66ff','#9966ff','#cc33ff'],
['#663300','#996600','#996633','#cc9900','#a58800','#cccc00','#ffff66','#ffff99','#ffffcc','#ffcccc'],
['#336600','#669900','#009900','#009933','#00cc00','#66ff66','#339933','#339966','#009999','#33cccc'],
['#003366','#336699','#3366cc','#0099ff','#000099','#0000cc','#660066','#993366','#993333','#800000']
],
pickerColor:'',
pickerArr:[-1,-1]
};
},
methods: {
picker(e) {
let data=e.currentTarget.dataset;
this.pickerColor=data.color;
this.pickerArr=[data.index,data.i];
},
hide(){
this.$emit("callback",'');
},
setColor(){
this.$emit("callback",this.pickerColor);
}
},
}
</script>
<style scoped>
.shade{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
z-index: 99;
}
.pop{
position: fixed;
right: 0;
bottom: 0;
left: 0;
background-color: #fff;
z-index: 100;
padding: 20upx 20upx 10upx 20upx;
font-size: 32upx;
}
.flex_col{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
align-content: center;
}
.list{
justify-content: space-between;
}
.list>view{
width: 60upx;
height: 60upx;
margin-bottom: 10upx;
box-sizing: border-box;
border-radius: 3px;
box-shadow: 0 0 2px #ccc;
}
.list .active{
box-shadow: 0 0 2px #09f;
transform:scale(1.05,1.05);
}
.preview{
width: 180upx;
height: 60upx;
}
.value{
margin: 0 40upx;
flex-grow: 1;
}
.ok{
width: 160upx;
height: 60upx;
line-height: 60upx;
text-align: center;
background-color: #ff9933;
color: #fff;
border-radius: 4px;
letter-spacing: 3px;
font-size: 32upx;
}
.ok:active{
background-color: rgb(255, 107, 34);
}
</style>

View File

@ -5,9 +5,8 @@
</template>
<script setup>
import {
$uploadFile
} from '@/http/yskApi/file.js'
import { uploadFile } from '@/api/index.js'
import {
reactive,
ref,
@ -64,10 +63,11 @@
function FileUploadselect(e) {
for (let i in e.tempFiles) {
const file = e.tempFiles[i]
$uploadFile(file).then(res => {
console.log(e)
uploadFile(file).then(res => {
console.log(res);
imgList.value.push({
url: res.data[0],
url: res,
path: file.path
})
}).catch(res=>{

View File

@ -10,6 +10,7 @@ const appConfig = {
// 环境变量相关
env: {},
wss: "wss://sockets.sxczgkj.com/wss",
// 环境变量常量
ENV_ENUM: {
DEVELOPMENT: 'development', // 本地调试地址

1
env/config.js vendored
View File

@ -29,7 +29,6 @@ const processEnv = process.env.NODE_ENV
// 改变env环境
function changeEnv(envMode){
appConfig.env = allEnvMap[envMode || processEnv]
// // 动态导包的方式设置全局env配置项目 : 当参数不存在, 那么获取node环境

View File

@ -1,8 +0,0 @@
{
"extEnable": true,
"extAppid":"wx9b4f8ff05754599f",
"directCommit": false,
"ext": {
"name": "wechat"
}
}

View File

@ -1,47 +0,0 @@
import request from './businessHttp.js'
import useStorage from '@/commons/utils/useStroage.js'
/**
* 登录
* @param {Object} data
*/
export function login(data) {
return request('/login/wx/merchant/login', data, 'post')
}
/**
* 桌台列表
* @param {Object} areaId
*/
export function tableList(areaId) {
return request('/table/list', {
shopId: useStorage.get('userInfo').shopId,
areaId: areaId
}, 'post')
}
/**
* 区域列表
* @param {Object} data
*/
export function areaList(data) {
return request('/table/area', {
shopId: useStorage.get('userInfo').shopId
})
}
/**
* 绑定桌码
* @param {Object} data
*/
export function tableBinding(data) {
return request('/table/binding', data, 'post')
}
/**
* 登录获取openid
* @param {Object} data
*/
export function wxlogin(data) {
return request('/login/wx/business/login', data)
}

View File

@ -1,52 +0,0 @@
/**
* 因为两个小程序接口不一致餐饮商超商家端的接口使用该http
*/
import useStorage from '@/commons/utils/useStroage.js'
import go from '@/commons/utils/go.js';
// const baseURL = 'http://192.168.2.128:9000/cashierService'
// const baseURL = 'http://192.168.2.41:9888/cashierService'
let baseURL = 'https://wxcashiertest.sxczgkj.cn/cashierService'
// #ifdef H5
baseURL = '/ysk'
// #endif
// const baseURL = 'https://cashier.sxczgkj.cn/cashierService'
export default function(api = '', data = {}, method = 'GET') {
return new Promise((resolve, reject) => {
uni.request({
url: `${baseURL}${api}`,
method: method,
data: data,
header: {
'environment': 'wx',
'type': 'ios',
'version': '1.0.0',
'token': useStorage.get('iToken'),
'Authorization': useStorage.get('iToken'),
'Content-Type': 'application/json'
},
success: res => {
if (res.data.code == 0) {
resolve(res.data)
} else {
uni.showToast({
icon: 'none',
"title": res.data.msg
})
if(res.data.code==-4){
setTimeout(()=>{
go.to('PAGES_LOGIN', {}, 'redirect')
},2000)
}
reject(res.data.msg)
}
},
fail: err => {
uni.showToast({
icon: 'none',
"title": err.errMsg
})
reject(err)
}
})
})
}

View File

@ -10,64 +10,77 @@
// 导入全局属性
import appConfig from '@/config/appConfig.js'
import storageManage from '@/commons/utils/storageManage.js'
import { sm4DecryptByResData } from '@/commons/utils/encryptUtil.js'
import {
sm4DecryptByResData
} from '@/commons/utils/encryptUtil.js'
import infoBox from "@/commons/utils/infoBox.js"
import go from '@/commons/utils/go.js';
let baseUrl = 'http://101.37.12.135:8080'
// #ifdef H5
baseUrl = '/server3/mch'
// #endif
// #ifndef H5
baseUrl = 'http://101.37.12.135:8080/mch'
// #endif
import { reject } from 'lodash';
// 测试服
let baseUrl = 'https://tapi.cashier.sxczgkj.cn/'
//预发布
// let baseUrl = 'https://pre-cashieradmin.sxczgkj.cn'
//正式
// let baseUrl = 'https://cashieradmin.sxczgkj.cn'
// 多少 ms 以内, 不提示loading
const loadingShowTime = 200
function getHeader(){
const headerObject={}
headerObject["token"] = storageManage.token()
return headerObject
}
// 通用处理逻辑
function commonsProcess(showLoading, httpReqCallback){
function commonsProcess(showLoading, httpReqCallback) {
// 判断是否请求完成(用作 是否loading
// 包括: 'ing', 'ingLoading', 'finish'
let reqState = 'ing'
// 是否已经提示的错误信息
let isShowErrorToast = false
let isShowErrorToast = false
// 请求完成, 需要处理的动作
let reqFinishFunc = () => {
if(reqState == 'ingLoading'){ // 关闭loading弹层
infoBox.hideLoading()
if (reqState == 'ingLoading') { // 关闭loading弹层
infoBox.hideLoading()
}
reqState = 'finish' // 请求完毕
}
// 明确显示loading
if(showLoading){
if (showLoading) {
// xx ms内响应完成不提示loading
setTimeout(() => {
if(reqState == 'ing'){
reqState = 'ingLoading'
infoBox.showLoading()
}
}, loadingShowTime)
if (reqState == 'ing') {
reqState = 'ingLoading'
infoBox.showLoading()
}
}, loadingShowTime)
}
return httpReqCallback().then((httpData) => {
reqFinishFunc(); // 请求完毕的动作
// 从http响应数据中解构响应数据 [ 响应码、 bodyData ]
let { statusCode, data } = httpData
let {
statusCode,
data
} = httpData
// 避免混淆重新命名
let bodyData = data
if(statusCode == 401){
// 清楚 token
storageManage.token(null, true)
if (statusCode == 500) {
isShowErrorToast = true
return Promise.reject(bodyData) // 跳转到catch函数
}
if (statusCode == 501) {
// storageManage.token(null, true)
// 提示信息
isShowErrorToast = true
// infoBox.showErrorToast('请登录').then(() => {
@ -76,86 +89,147 @@ function commonsProcess(showLoading, httpReqCallback){
return Promise.reject(bodyData) // 跳转到catch函数
}
// http响应码不正确
if(statusCode != 200){
if (statusCode != 200 && statusCode != 204 && statusCode != 201) {
isShowErrorToast = true
infoBox.showToast('服务器异常')
bodyData.msg=bodyData.msg=='Bad credentials'?'用户名或密码错误':bodyData.msg
infoBox.showToast(bodyData.msg || '服务器异常')
return Promise.reject(bodyData) // 跳转到catch函数
}
// 业务响应异常
if(bodyData.code != 0){
// // 业务响应异常
if (bodyData.hasOwnProperty('code') && bodyData.code != 200) {
isShowErrorToast = true
infoBox.showToast(bodyData.msg)
if(bodyData.code == 5005){ // 密码已过期, 直接跳转到更改密码页面
uni.reLaunch({url: '/pageUser/setting/updatePwd'})
}
if(bodyData.code == 500){ // 密码已过期, 直接跳转到更改密码页面
uni.redirectTo({url: '/pages/login/index'})
}
return Promise.reject(bodyData)
// if (bodyData.code == 5005) { // 密码已过期, 直接跳转到更改密码页面
// uni.reLaunch({
// url: '/pageUser/setting/updatePwd'
// })
// }
// if(bodyData.code == 500){ // 密码已过期, 直接跳转到更改密码页面
// uni.redirectTo({url: '/pages/login/index'})
// }
return Promise.reject(bodyData) // 跳转到catch函数
}
// 加密数据
if(!bodyData.data && bodyData.encryptData){
return Promise.resolve({ bizData: sm4DecryptByResData(bodyData.encryptData), code: bodyData.code })
if (!bodyData.data && bodyData.encryptData) {
return Promise.resolve({
bizData: sm4DecryptByResData(bodyData.encryptData),
code: bodyData.code
})
}
// 构造请求成功的响应数据
return Promise.resolve({ bizData: bodyData.data, code: bodyData.code })
}).catch( res => {
return Promise.resolve(bodyData.data)
}).catch(res => {
console.log(res)
if(res.code==501){
storageManage.token(null, true)
infoBox.showToast(res.msg||'请登录').then(() => {
uni.redirectTo({url: '/pages/login/index'})
reject()
})
}
// if(res.status==400){
// storageManage.token(null, true)
// infoBox.showErrorToast('').then(() => {
// go.to("PAGES_LOGIN", {}, go.GO_TYPE_RELAUNCH)
// })
// }
if(res.code==500){
infoBox.showToast(res.msg||'服务器异常').then(() => {})
}
// if(res&&res.msg){
// infoBox.showErrorToast(res.msg)
// }
reqFinishFunc(); // 请求完毕的动作
// 如果没有提示错误, 那么此处提示 异常。
if(!isShowErrorToast){
if (!isShowErrorToast) {
infoBox.showToast(`请求网络异常`)
}
return Promise.reject(res)
}).finally(() => { // finally 是 then结束后再执行, 此处不适用。 需要在请求完成后立马调用: reqFinishFunc()
});
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function req(uri, data, method = "GET", showLoading = true, extParams = {}){
// 放置token
let headerObject = {}
headerObject[appConfig.tokenKey] = storageManage.token()
headerObject["satoken"] = storageManage.token()
function req(uri, data, method = "GET", showLoading = true, extParams = {}) {
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign({url: baseUrl + uri, data: data, method: method, header: headerObject}, extParams )
)
}
)
return uni.request(
Object.assign({
url: baseUrl + uri,
data: data,
method: method,
header: getHeader()
}, extParams)
)
})
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function request(args) {
const {
url,
data,
params,
method = "GET",
showLoading = true,
extParams = {}
} = args
let headerObject = {}
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign({
url: baseUrl + url,
data: params||data,
method: method,
header: getHeader()
}, extParams)
)
})
}
// 上传
function upload(uri, data, file, showLoading = true, extParams = {}){
function upload(uri, data, file, showLoading = true, extParams = {}) {
// 放置token
let headerObject = {}
headerObject[appConfig.tokenKey] = storageManage.token()
// headerObject[appConfig.tokenKey] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.uploadFile(
Object.assign({url: baseUrl + uri, formData: data, name: "file", filePath: file.path, header: headerObject}, extParams )
).then((httpData) => {
// uni.upload 返回bodyData 的是 string类型。 需要解析。
httpData.data = JSON.parse(httpData.data)
return Promise.resolve(httpData)
})
}
)
return uni.uploadFile(
Object.assign({
url: baseUrl + uri,
formData: data,
name: "file",
filePath: file.path||file.url,
header: getHeader()
}, extParams)
).then((httpData) => {
// uni.upload 返回bodyData 的是 string类型。 需要解析。
httpData.data = JSON.parse(httpData.data)
return Promise.resolve(httpData)
}).catch(err=>{
uni.hideLoading()
infoBox.showErrorToast(`上传失败`)
})
})
}
export default {
req : req,
upload : upload
}
req: req,
request,
upload: upload
}

View File

@ -1,182 +0,0 @@
/**
* HTTP的封装 基于uni.request
* 包括 通用响应结果的处理 业务的增删改查函数
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/12/16 18:35
*/
// 导入全局属性
import appConfig from '@/config/appConfig.js'
import storageManage from '@/commons/utils/storageManage.js'
import {
sm4DecryptByResData
} from '@/commons/utils/encryptUtil.js'
import infoBox from "@/commons/utils/infoBox.js"
import go from '@/commons/utils/go.js';
let baseUrl = 'http://101.37.12.135:8080'
// #ifdef H5
baseUrl = '/server3'
// #endif
// 多少 ms 以内, 不提示loading
const loadingShowTime = 200
// 通用处理逻辑
function commonsProcess(showLoading, httpReqCallback) {
// 判断是否请求完成(用作 是否loading
// 包括: 'ing', 'ingLoading', 'finish'
let reqState = 'ing'
// 是否已经提示的错误信息
let isShowErrorToast = false
// 请求完成, 需要处理的动作
let reqFinishFunc = () => {
if (reqState == 'ingLoading') { // 关闭loading弹层
infoBox.hideLoading()
}
reqState = 'finish' // 请求完毕
}
// 明确显示loading
if (showLoading) {
// xx ms内响应完成不提示loading
setTimeout(() => {
if (reqState == 'ing') {
reqState = 'ingLoading'
infoBox.showLoading()
}
}, loadingShowTime)
}
return httpReqCallback().then((httpData) => {
console.log(httpData);
reqFinishFunc(); // 请求完毕的动作
// 从http响应数据中解构响应数据 [ 响应码、 bodyData ]
let {
statusCode,
data
} = httpData
// 避免混淆重新命名
let bodyData = data
if (statusCode == 401) {
// 清楚 token
storageManage.token(null, true)
// 提示信息
isShowErrorToast = true
infoBox.showErrorToast('请登录').then(() => {
go.to("PAGES_LOGIN", {}, go.GO_TYPE_RELAUNCH)
})
return Promise.reject(bodyData) // 跳转到catch函数
}
// http响应码不正确
if (statusCode != 200) {
isShowErrorToast = true
infoBox.showErrorToast('服务器异常')
return Promise.reject(bodyData) // 跳转到catch函数
}
// 业务响应异常
if (bodyData.code != 200) {
isShowErrorToast = true
infoBox.showToast(bodyData.msg)
if (bodyData.code == 5005) { // 密码已过期, 直接跳转到更改密码页面
uni.reLaunch({
url: '/pageUser/setting/updatePwd'
})
}
if(bodyData.code == 500){ // 密码已过期, 直接跳转到更改密码页面
uni.redirectTo({url: '/pages/login/index'})
}
return Promise.reject(bodyData)
}
// 加密数据
if (!bodyData.data && bodyData.encryptData) {
return Promise.resolve({
bizData: sm4DecryptByResData(bodyData.encryptData),
code: bodyData.code
})
}
// 构造请求成功的响应数据
return Promise.resolve({
bizData: bodyData.data,
code: bodyData.code
})
}).catch(res => {
reqFinishFunc(); // 请求完毕的动作
// 如果没有提示错误, 那么此处提示 异常。
if (!isShowErrorToast) {
infoBox.showErrorToast(`请求网络异常`)
}
return Promise.reject(res)
}).finally(() => { // finally 是 then结束后再执行, 此处不适用。 需要在请求完成后立马调用: reqFinishFunc()
});
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function req(uri, data, method = "GET", showLoading = true, extParams = {}) {
let headerObject = {}
// headerObject[appConfig.tokenKey] = storageManage.token()
headerObject["satoken"] = storageManage.token()
headerObject["content-type"] = 'application/json'
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign({
url: baseUrl + uri,
data: data,
method: method,
header: headerObject
}, extParams)
)
})
}
// 上传
function upload(uri, data, file, showLoading = true, extParams = {}) {
// 放置token
let headerObject = {}
// headerObject[appConfig.tokenKey] = storageManage.token()
headerObject["satoken"] = storageManage.token()
return commonsProcess(showLoading, () => {
return uni.uploadFile(
Object.assign({
url: appConfig.env.JEEPAY_BASE_URL + uri,
formData: data,
name: "file",
filePath: file.path,
header: headerObject
}, extParams)
).then((httpData) => {
// uni.upload 返回bodyData 的是 string类型。 需要解析。
httpData.data = JSON.parse(httpData.data)
return Promise.resolve(httpData)
})
})
}
export default {
req: req,
upload: upload
}

View File

@ -1,11 +0,0 @@
import http from './http.js'
import appConfig from '@/config/appConfig.js'
import {
Base64
} from 'js-base64'
import infoBox from '@/commons/utils/infoBox.js'
/* 登录 */
export function $login(postData) {
// return http.req('/login', params, 'GET')
return http.req('/login', postData, 'POST')
}

View File

@ -16,8 +16,9 @@ import {
import infoBox from "@/commons/utils/infoBox.js"
import go from '@/commons/utils/go.js';
import { reject } from 'lodash';
// 测试服
let baseUrl = 'https://admintestpapi.sxczgkj.cn'
let baseUrl = 'https://tapi.cashier.sxczgkj.cn/'
//预发布
// let baseUrl = 'https://pre-cashieradmin.sxczgkj.cn'

View File

@ -1,44 +0,0 @@
/*
* $Id: dankogai.js,v 0.4 2012/08/24 05:23:18 dankogai Exp dankogai $
*
* use mocha to test me
* http://visionmedia.github.com/mocha/
*/
var assert = assert || require("assert");
var Base64 = Base64 || require('../base64.js').Base64;
var is = function (a, e, m) {
return function () {
assert.equal(a, e, m)
}
};
describe('basic', function () {
it('d', is(Base64.encode('d'), 'ZA=='));
it('da', is(Base64.encode('da'), 'ZGE='));
it('dan', is(Base64.encode('dan'), 'ZGFu'));
it('ZA==', is(Base64.decode('ZA=='), 'd' ));
it('ZGE=', is(Base64.decode('ZGE='), 'da' ));
it('ZGFu', is(Base64.decode('ZGFu'), 'dan' ));
});
describe('whitespace', function () {
it('Z A==', is(Base64.decode('ZA =='), 'd' ));
it('ZG E=', is(Base64.decode('ZG E='), 'da' ));
it('ZGF u', is(Base64.decode('ZGF u'), 'dan' ));
});
describe('null', function () {
it('\\0', is(Base64.encode('\0'), 'AA=='));
it('\\0\\0', is(Base64.encode('\0\0'), 'AAA='));
it('\\0\\0\\0', is(Base64.encode('\0\0\0'), 'AAAA'));
it('AA==', is(Base64.decode('AA=='), '\0' ));
it('AAA=', is(Base64.decode('AAA='), '\0\0' ));
it('AAAA', is(Base64.decode('AAAA'), '\0\0\0'));
});
describe('Base64', function () {
it('.encode', is(Base64.encode('小飼弾'), '5bCP6aO85by+'));
it('.encodeURI', is(Base64.encodeURI('小飼弾'), '5bCP6aO85by-'));
it('.decode', is(Base64.decode('5bCP6aO85by+'), '小飼弾'));
it('.decode', is(Base64.decode('5bCP6aO85by-'), '小飼弾'));
});

View File

@ -1,24 +0,0 @@
/*
* $Id: es5.js,v 0.1 2012/08/23 19:43:17 dankogai Exp dankogai $
*
* use mocha to test me
* http://visionmedia.github.com/mocha/
*/
var assert = assert || require("assert");
var Base64 = Base64 || require('../base64.js').Base64;
var is = function (a, e, m) {
return function () {
assert.equal(a, e, m)
}
};
if ('extendString' in Base64){
Base64.extendString();
describe('String', function () {
it('.toBase64', is('小飼弾'.toBase64(), '5bCP6aO85by+'));
it('.toBase64', is('小飼弾'.toBase64(true), '5bCP6aO85by-'));
it('.toBase64URI', is('小飼弾'.toBase64URI(), '5bCP6aO85by-'));
it('.fromBase64', is('5bCP6aO85by+'.fromBase64(), '小飼弾'));
it('.fromBase64', is('5bCP6aO85by-'.fromBase64(), '小飼弾'));
});
}

View File

@ -1,25 +0,0 @@
/*
* $Id: es6.js,v 0.1 2017/11/29 21:43:17 ufolux Exp ufolux $
*
* use mocha to test me
* http://visionmedia.github.com/mocha/
*/
import {Base64} from '../base64'
var assert = assert || require("assert");
var is = function (a, e, m) {
return function () {
assert.equal(a, e, m)
}
};
if ('extendString' in Base64){
Base64.extendString();
describe('String', function () {
it('.toBase64', is('小飼弾'.toBase64(), '5bCP6aO85by+'));
it('.toBase64', is('小飼弾'.toBase64(true), '5bCP6aO85by-'));
it('.toBase64URI', is('小飼弾'.toBase64URI(), '5bCP6aO85by-'));
it('.fromBase64', is('5bCP6aO85by+'.fromBase64(), '小飼弾'));
it('.fromBase64', is('5bCP6aO85by-'.fromBase64(), '小飼弾'));
});
}

View File

@ -1,40 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<title>Mocha Tests</title>
<link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
</head>
<body>
<div id="mocha"></div>
<script src="https://cdn.rawgit.com/jquery/jquery/2.1.4/dist/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/Automattic/expect.js/0.3.1/index.js"></script>
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<script>
mocha.setup('bdd');
</script>
<script src="./moment.js"></script>
<script src="../base64.js"></script>
<script>
var assert = function(expr, msg) {
if (!expr) throw new Error(msg || 'failed');
};
assert.equal = function(a, b, msg) {
if (a !== b) throw new Error(msg || ('failed : '+a+','+b));
};
</script>
<script src="./dankogai.js"></script>
<script src="./es5.js"></script>
<script src="./large.js"></script>
<script src="./yoshinoya.js"></script>
<script>
$(function() {
mocha.run();
});
</script>
</head>
<body>
$Id: index.html,v 0.3 2017/09/11 08:43:43 dankogai Exp dankogai $
<div id="mocha"></div>
</body>
</html>

View File

@ -1,25 +0,0 @@
/*
* $Id: large.js,v 0.3 2012/08/23 19:14:37 dankogai Exp dankogai $
*
* use mocha to test me
* http://visionmedia.github.com/mocha/
*/
var assert = assert || require("assert");
var Base64 = Base64 || require('../base64.js').Base64;
var is = function (a, e, m) {
return function () {
assert.equal(a, e, m)
}
};
var seed = function () {
var a, i;
for (a = [], i = 0; i < 256; i++) {
a.push(String.fromCharCode(i));
}
return a.join('');
}();
describe('Base64', function () {
for (var i = 0, str = seed; i < 16; str += str, i++) {
it(''+str.length, is(Base64.decode(Base64.encode(str)), str));
}
});

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
/*
* use mocha to test me
* http://visionmedia.github.com/mocha/
*/
var assert = assert || require("assert");
var Base64 = Base64 || require('../base64.js').Base64;
var is = function (a, e, m) {
return function () {
assert.equal(a, e, m)
}
};
describe('Yoshinoya', function () {
it('.encode', is(Base64.encode('𠮷野家'), '8KCut+mHjuWutg=='));
it('.encodeURI', is(Base64.encodeURI('𠮷野家'), '8KCut-mHjuWutg'));
it('.decode', is(Base64.decode('8KCut+mHjuWutg=='), '𠮷野家'));
it('.decode', is(Base64.decode('8KCut-mHjuWutg'), '𠮷野家'));
/* it('.decode', is(Base64.decode('7aGC7b636YeO5a62'), '𠮷野家')); */
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

View File

@ -1,27 +0,0 @@
Copyright (c) 2014, Dan Kogai
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of {{{project}}} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,94 +0,0 @@
[![build status](https://secure.travis-ci.org/dankogai/js-base64.png)](http://travis-ci.org/dankogai/js-base64)
# base64.js
Yet another Base64 transcoder
## Install
```javascript
$ npm install --save js-base64
```
If you are using it on ES6 transpilers, you may also need:
```javascript
$ npm install --save babel-preset-env
```
Note `js-base64` itself is stand-alone so its `package.json` has no `dependencies`.  However, it is also tested on ES6 environment so `"babel-preset-env": "^1.7.0"` is on `devDependencies`.
## Usage
### In Browser
```html
<script src="base64.js"></script>
```
### node.js
```javascript
var Base64 = require('js-base64').Base64;
```
## es6+
```javascript
import { Base64 } from 'js-base64';
```
## SYNOPSIS
```javascript
Base64.encode('dankogai'); // ZGFua29nYWk=
Base64.encode('小飼弾'); // 5bCP6aO85by+
Base64.encodeURI('小飼弾'); // 5bCP6aO85by-
Base64.decode('ZGFua29nYWk='); // dankogai
Base64.decode('5bCP6aO85by+'); // 小飼弾
// note .decodeURI() is unnecessary since it accepts both flavors
Base64.decode('5bCP6aO85by-'); // 小飼弾
```
### String Extension for ES5
```javascript
if (Base64.extendString) {
// you have to explicitly extend String.prototype
Base64.extendString();
// once extended, you can do the following
'dankogai'.toBase64(); // ZGFua29nYWk=
'小飼弾'.toBase64(); // 5bCP6aO85by+
'小飼弾'.toBase64(true); // 5bCP6aO85by-
'小飼弾'.toBase64URI(); // 5bCP6aO85by-
'ZGFua29nYWk='.fromBase64(); // dankogai
'5bCP6aO85by+'.fromBase64(); // 小飼弾
'5bCP6aO85by-'.fromBase64(); // 小飼弾
}
```
### TypeScript
TypeScript 2.0 type definition was added to the [DefinitelyTyped repository](https://github.com/DefinitelyTyped/DefinitelyTyped).
```bash
$ npm install --save @types/js-base64
```
## `.decode()` vs `.atob` (and `.encode()` vs `btoa()`)
Suppose you have:
```
var pngBase64 =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
```
Which is a Base64-encoded 1x1 transparent PNG, **DO NOT USE** `Base64.decode(pngBase64)`.  Use `Base64.atob(pngBase64)` instead.  `Base64.decode()` decodes to UTF-8 string while `Base64.atob()` decodes to bytes, which is compatible to browser built-in `atob()` (Which is absent in node.js).  The same rule applies to the opposite direction.
## SEE ALSO
+ http://en.wikipedia.org/wiki/Base64

View File

@ -1,47 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- $Id: base64.html,v 1.1 2009/03/01 22:00:28 dankogai Exp dankogai $ -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Demo for base64.js</title>
</head>
<body>
<h1>Demo for base64.js</h1>
<p>$Id: base64.html,v 1.1 2009/03/01 22:00:28 dankogai Exp dankogai $</p>
<table width="640"><tbody>
<tr><th width="50%">Text</th><th>Base64
(URL Safe <input id="encodeURI" type="checkbox" onclick="doit()">)</th></tr>
<tr>
<th><textarea id="srctxt" cols="32" rows="4" onkeyup="doit()">
</textarea></th>
<th><textarea id="base64" cols="32" rows="4" onkeyup="
$('srctxt').value = Base64.decode(this.value);
doit();
if (1 /*@cc_on -1 @*/) $('data').src = 'data:text/plain;base64,' + this.value;
"></textarea></th>
</tr>
<tr><th width="50%">Roundtrip</th><th>iframe w/ data: (no IE)</th></tr>
<tr>
<th><textarea id="roundtrip" cols=32" rows="4" disabled></textarea></th>
<th><iframe id="data" width="80%" height="64"></iframe></th>
</tr>
</tbody></table>
<script src="./base64.js"></script>
<script>
$ = function(id){ return document.getElementById(id) };
function doit(){
var encoded = Base64[
'encode' + ($('encodeURI').checked ? 'URI' : '')
]($('srctxt').value);
$('base64').value = encoded;
if (1 /*@cc_on -1 @*/) {
$('data').src = 'data:text/plain;base64,'
+ Base64.encode(Base64.decode(encoded));
}
$('roundtrip').value = Base64.decode(encoded);
}
</script>
</body>
</html>

View File

@ -1,231 +0,0 @@
/*
* base64.js
*
* Licensed under the BSD 3-Clause License.
* http://opensource.org/licenses/BSD-3-Clause
*
* References:
* http://en.wikipedia.org/wiki/Base64
*/
;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? module.exports = factory(global)
: typeof define === 'function' && define.amd
? define(factory) : factory(global)
}((
typeof self !== 'undefined' ? self
: typeof window !== 'undefined' ? window
: typeof global !== 'undefined' ? global
: this
), function(global) {
'use strict';
// existing version for noConflict()
var _Base64 = global.Base64;
var version = "2.4.9";
// if node.js and NOT React Native, we use Buffer
var buffer;
if (typeof module !== 'undefined' && module.exports) {
try {
buffer = eval("require('buffer').Buffer");
} catch (err) {
buffer = undefined;
}
}
// constants
var b64chars
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var b64tab = function(bin) {
var t = {};
for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
return t;
}(b64chars);
var fromCharCode = String.fromCharCode;
// encoder stuff
var cb_utob = function(c) {
if (c.length < 2) {
var cc = c.charCodeAt(0);
return cc < 0x80 ? c
: cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6))
+ fromCharCode(0x80 | (cc & 0x3f)))
: (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f))
+ fromCharCode(0x80 | ((cc >>> 6) & 0x3f))
+ fromCharCode(0x80 | ( cc & 0x3f)));
} else {
var cc = 0x10000
+ (c.charCodeAt(0) - 0xD800) * 0x400
+ (c.charCodeAt(1) - 0xDC00);
return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07))
+ fromCharCode(0x80 | ((cc >>> 12) & 0x3f))
+ fromCharCode(0x80 | ((cc >>> 6) & 0x3f))
+ fromCharCode(0x80 | ( cc & 0x3f)));
}
};
var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
var utob = function(u) {
return u.replace(re_utob, cb_utob);
};
var cb_encode = function(ccc) {
var padlen = [0, 2, 1][ccc.length % 3],
ord = ccc.charCodeAt(0) << 16
| ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8)
| ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
chars = [
b64chars.charAt( ord >>> 18),
b64chars.charAt((ord >>> 12) & 63),
padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
];
return chars.join('');
};
var btoa = global.btoa ? function(b) {
return global.btoa(b);
} : function(b) {
return b.replace(/[\s\S]{1,3}/g, cb_encode);
};
var _encode = buffer ?
buffer.from && Uint8Array && buffer.from !== Uint8Array.from
? function (u) {
return (u.constructor === buffer.constructor ? u : buffer.from(u))
.toString('base64')
}
: function (u) {
return (u.constructor === buffer.constructor ? u : new buffer(u))
.toString('base64')
}
: function (u) { return btoa(utob(u)) }
;
var encode = function(u, urisafe) {
return !urisafe
? _encode(String(u))
: _encode(String(u)).replace(/[+\/]/g, function(m0) {
return m0 == '+' ? '-' : '_';
}).replace(/=/g, '');
};
var encodeURI = function(u) { return encode(u, true) };
// decoder stuff
var re_btou = new RegExp([
'[\xC0-\xDF][\x80-\xBF]',
'[\xE0-\xEF][\x80-\xBF]{2}',
'[\xF0-\xF7][\x80-\xBF]{3}'
].join('|'), 'g');
var cb_btou = function(cccc) {
switch(cccc.length) {
case 4:
var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
| ((0x3f & cccc.charCodeAt(1)) << 12)
| ((0x3f & cccc.charCodeAt(2)) << 6)
| (0x3f & cccc.charCodeAt(3)),
offset = cp - 0x10000;
return (fromCharCode((offset >>> 10) + 0xD800)
+ fromCharCode((offset & 0x3FF) + 0xDC00));
case 3:
return fromCharCode(
((0x0f & cccc.charCodeAt(0)) << 12)
| ((0x3f & cccc.charCodeAt(1)) << 6)
| (0x3f & cccc.charCodeAt(2))
);
default:
return fromCharCode(
((0x1f & cccc.charCodeAt(0)) << 6)
| (0x3f & cccc.charCodeAt(1))
);
}
};
var btou = function(b) {
return b.replace(re_btou, cb_btou);
};
var cb_decode = function(cccc) {
var len = cccc.length,
padlen = len % 4,
n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0)
| (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0)
| (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0)
| (len > 3 ? b64tab[cccc.charAt(3)] : 0),
chars = [
fromCharCode( n >>> 16),
fromCharCode((n >>> 8) & 0xff),
fromCharCode( n & 0xff)
];
chars.length -= [0, 0, 2, 1][padlen];
return chars.join('');
};
var atob = global.atob ? function(a) {
return global.atob(a);
} : function(a){
return a.replace(/[\s\S]{1,4}/g, cb_decode);
};
var _decode = buffer ?
buffer.from && Uint8Array && buffer.from !== Uint8Array.from
? function(a) {
return (a.constructor === buffer.constructor
? a : buffer.from(a, 'base64')).toString();
}
: function(a) {
return (a.constructor === buffer.constructor
? a : new buffer(a, 'base64')).toString();
}
: function(a) { return btou(atob(a)) };
var decode = function(a){
return _decode(
String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' })
.replace(/[^A-Za-z0-9\+\/]/g, '')
);
};
var noConflict = function() {
var Base64 = global.Base64;
global.Base64 = _Base64;
return Base64;
};
// export Base64
global.Base64 = {
VERSION: version,
atob: atob,
btoa: btoa,
fromBase64: decode,
toBase64: encode,
utob: utob,
encode: encode,
encodeURI: encodeURI,
btou: btou,
decode: decode,
noConflict: noConflict,
__buffer__: buffer
};
// if ES5 is available, make Base64.extendString() available
if (typeof Object.defineProperty === 'function') {
var noEnum = function(v){
return {value:v,enumerable:false,writable:true,configurable:true};
};
global.Base64.extendString = function () {
Object.defineProperty(
String.prototype, 'fromBase64', noEnum(function () {
return decode(this)
}));
Object.defineProperty(
String.prototype, 'toBase64', noEnum(function (urisafe) {
return encode(this, urisafe)
}));
Object.defineProperty(
String.prototype, 'toBase64URI', noEnum(function () {
return encode(this, true)
}));
};
}
//
// export Base64 to the namespace
//
if (global['Meteor']) { // Meteor.js
Base64 = global.Base64;
}
// module.exports and AMD are mutually exclusive.
// module.exports has precedence.
if (typeof module !== 'undefined' && module.exports) {
module.exports.Base64 = global.Base64;
}
else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function(){ return global.Base64 });
}
// that's it!
return {Base64: global.Base64}
}));

View File

@ -1 +0,0 @@
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory(global):typeof define==="function"&&define.amd?define(factory):factory(global)})(typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:this,function(global){"use strict";var _Base64=global.Base64;var version="2.4.9";var buffer;if(typeof module!=="undefined"&&module.exports){try{buffer=eval("require('buffer').Buffer")}catch(err){buffer=undefined}}var b64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64tab=function(bin){var t={};for(var i=0,l=bin.length;i<l;i++)t[bin.charAt(i)]=i;return t}(b64chars);var fromCharCode=String.fromCharCode;var cb_utob=function(c){if(c.length<2){var cc=c.charCodeAt(0);return cc<128?c:cc<2048?fromCharCode(192|cc>>>6)+fromCharCode(128|cc&63):fromCharCode(224|cc>>>12&15)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}else{var cc=65536+(c.charCodeAt(0)-55296)*1024+(c.charCodeAt(1)-56320);return fromCharCode(240|cc>>>18&7)+fromCharCode(128|cc>>>12&63)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}};var re_utob=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;var utob=function(u){return u.replace(re_utob,cb_utob)};var cb_encode=function(ccc){var padlen=[0,2,1][ccc.length%3],ord=ccc.charCodeAt(0)<<16|(ccc.length>1?ccc.charCodeAt(1):0)<<8|(ccc.length>2?ccc.charCodeAt(2):0),chars=[b64chars.charAt(ord>>>18),b64chars.charAt(ord>>>12&63),padlen>=2?"=":b64chars.charAt(ord>>>6&63),padlen>=1?"=":b64chars.charAt(ord&63)];return chars.join("")};var btoa=global.btoa?function(b){return global.btoa(b)}:function(b){return b.replace(/[\s\S]{1,3}/g,cb_encode)};var _encode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(u){return(u.constructor===buffer.constructor?u:buffer.from(u)).toString("base64")}:function(u){return(u.constructor===buffer.constructor?u:new buffer(u)).toString("base64")}:function(u){return btoa(utob(u))};var encode=function(u,urisafe){return!urisafe?_encode(String(u)):_encode(String(u)).replace(/[+\/]/g,function(m0){return m0=="+"?"-":"_"}).replace(/=/g,"")};var encodeURI=function(u){return encode(u,true)};var re_btou=new RegExp(["[À-ß][€-¿]","[à-ï][€-¿]{2}","[ð-÷][€-¿]{3}"].join("|"),"g");var cb_btou=function(cccc){switch(cccc.length){case 4:var cp=(7&cccc.charCodeAt(0))<<18|(63&cccc.charCodeAt(1))<<12|(63&cccc.charCodeAt(2))<<6|63&cccc.charCodeAt(3),offset=cp-65536;return fromCharCode((offset>>>10)+55296)+fromCharCode((offset&1023)+56320);case 3:return fromCharCode((15&cccc.charCodeAt(0))<<12|(63&cccc.charCodeAt(1))<<6|63&cccc.charCodeAt(2));default:return fromCharCode((31&cccc.charCodeAt(0))<<6|63&cccc.charCodeAt(1))}};var btou=function(b){return b.replace(re_btou,cb_btou)};var cb_decode=function(cccc){var len=cccc.length,padlen=len%4,n=(len>0?b64tab[cccc.charAt(0)]<<18:0)|(len>1?b64tab[cccc.charAt(1)]<<12:0)|(len>2?b64tab[cccc.charAt(2)]<<6:0)|(len>3?b64tab[cccc.charAt(3)]:0),chars=[fromCharCode(n>>>16),fromCharCode(n>>>8&255),fromCharCode(n&255)];chars.length-=[0,0,2,1][padlen];return chars.join("")};var atob=global.atob?function(a){return global.atob(a)}:function(a){return a.replace(/[\s\S]{1,4}/g,cb_decode)};var _decode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(a){return(a.constructor===buffer.constructor?a:buffer.from(a,"base64")).toString()}:function(a){return(a.constructor===buffer.constructor?a:new buffer(a,"base64")).toString()}:function(a){return btou(atob(a))};var decode=function(a){return _decode(String(a).replace(/[-_]/g,function(m0){return m0=="-"?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))};var noConflict=function(){var Base64=global.Base64;global.Base64=_Base64;return Base64};global.Base64={VERSION:version,atob:atob,btoa:btoa,fromBase64:decode,toBase64:encode,utob:utob,encode:encode,encodeURI:encodeURI,btou:btou,decode:decode,noConflict:noConflict,__buffer__:buffer};if(typeof Object.defineProperty==="function"){var noEnum=function(v){return{value:v,enumerable:false,writable:true,configurable:true}};global.Base64.extendString=function(){Object.defineProperty(String.prototype,"fromBase64",noEnum(function(){return decode(this)}));Object.defineProperty(String.prototype,"toBase64",noEnum(function(urisafe){return encode(this,urisafe)}));Object.defineProperty(String.prototype,"toBase64URI",noEnum(function(){return encode(this,true)}))}}if(global["Meteor"]){Base64=global.Base64}if(typeof module!=="undefined"&&module.exports){module.exports.Base64=global.Base64}else if(typeof define==="function"&&define.amd){define([],function(){return global.Base64})}return{Base64:global.Base64}});

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