commit db4a95e35d8cde0bdc2969acc7d8112c7e2f8b43 Author: whitechiina <1293616053@qq.com> Date: Tue Nov 25 11:21:13 2025 +0800 first commit diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..99f6e28 --- /dev/null +++ b/App.vue @@ -0,0 +1,17 @@ + + + diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..e38e827 --- /dev/null +++ b/api/index.js @@ -0,0 +1,90 @@ +import request from "@/utils/request.js"; + +// 推送播报 +export function cancelPaymentSoundAPI(data) { + return request.get('MiniProgram/Order/cancelPaymentSound', data); +} + +// 取消发声 +export function cancelPay(data) { + return request.post('/api/gzh/cancelPay', data); +} + +// 获取商户信息 +export function getMerchantAPI(data) { + return request.get('MiniProgram/Api/getMerchant', data); +} + +// 获取用户信息 +export function userInfoAPI(data) { + return request.get('MiniProgram/Api/userInfo', data); +} + +// 支付 +export function createScanOrderAPI(data) { + return request.get('MiniProgram/Api/submitOrder', data); +} + +// 发送验证码 +export function sendSmsAPI(data) { + return request.get('MiniProgram/Api/sendSms', data); +} + +// 绑定手机号 +export function bindPhoneAPI(data) { + return request.get('MiniProgram/Api/bindPhone', data); +} + +// 商户端支付 +export function againPayAPI(data) { + return request.get('client/mall/againPay', data); +} + +// 订单详情? +export function orderDetailAPI(data) { + return request.get('MiniProgram/Api/orderDetail', data); +} + +// code查店铺 +export function getMerchantInfoByCode(data) { + return request.post('/api/gzh/getMerchantInfoByCode', data); +} + +// id查店铺 +export function getMerchantInfo(data) { + return request.post('/api/gzh/getMerchantInfo', data); +} + +// 下单 1 +export function doOrder(data) { + return request.post('/api/merchant/doOrder', data); +} + +// 下单 0 +export function dogzhOrder(data) { + return request.post('/api/gzh/doOrder', data); +} + +// 券 1 +export function computedOrder(data) { + return request.post('/api/merchant/computedOrder', data); +} + + +// 券 0 +export function gzhcomputedOrder(data) { + return request.post('/api/gzh/computedOrder', data); +} + +// 支付宝订单号查询 1 +export function getOfflineOrderDetail(data) { + return request.post('/api/merchant/getOfflineOrderDetail', data); +} + +// 支付宝订单号查询 0 +export function getgzhlineOrderDetail(data) { + return request.post('/api/gzh/getOfflineOrderDetail', data); +} + + + diff --git a/api/order.js b/api/order.js new file mode 100644 index 0000000..8e23ed4 --- /dev/null +++ b/api/order.js @@ -0,0 +1,448 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +import request from "@/utils/request.js"; + +/** + * 获取购物车列表 + * @param numType boolean true 购物车数量,false=购物车产品数量 + */ +export function getCartCounts(numType) { + return request.get("cart/count", { + numType: numType === undefined ? 0 : numType + }); +} +/** + * 获取购物车列表 + * + */ +export function getCartList(data) { + return request.get("cart/list", data); +} + +/** + * 修改购物车 + * + */ +export function getResetCart(data) { + return request.post("v2/reset_cart", data); +} + +/** + * 修改购物车数量 + * @param int cartId 购物车id + * @param int number 修改数量 + */ +export function changeCartNum(cartId, number) { + return request.post("cart/num", { + id: cartId, + number: number + }); +} +/** + * 清除购物车 + * @param object ids join(',') 切割成字符串 + */ +export function cartDel(ids) { + if (typeof ids === 'object') + ids = ids.join(','); + return request.post('cart/del', { + ids: ids + }); +} +/** + * 订单列表 + * @param object data + */ +export function getOrderList(data) { + return request.get('order/list', data); +} + +/** + * 订单产品信息 + * @param string unique + */ +export function orderProduct(unique) { + return request.post('order/product', { + unique: unique + }); +} + +/** + * 订单评价 + * @param object data + * + */ +export function orderComment(data) { + return request.post('order/comment', data); +} + +/** + * 订单支付 + * @param object data + */ +export function orderPay(data) { + return request.post('/api/order/pay', data); +} + +/** + * 删除已退款和拒绝退款的订单 + * @param string uni + * + */ +export function refundOrderDel(uni) { + return request.get('order/refund/del/' + uni, {}); +} + +/** + * 订单统计数据 + */ +export function orderData() { + return request.get('order/data') +} + +/** + * 订单取消 + * @param string id + * + */ +export function orderCancel(id) { + return request.post('mall/api/cancel_order', { + order_id: id + }); +} + +/** + * 删除已完成订单 + * @param string uni + * + */ +export function orderDel(uni) { + return request.post('order/del', { + uni: uni + }); +} + +/** + * 订单详情 + * @param string uni + */ +export function getOrderDetail(uni, cart_id) { + return request.get('order/detail/' + uni + `${cart_id ? `/${cart_id}`:''}`); +} +/** + * 退款订单详情 + * @param string uni + */ +export function getRefundOrderDetail(uni, cart_id) { + return request.get('order/refund_detail/' + uni + `${cart_id ? `/${cart_id}`:''}`); +} + +/** + * 再次下单 + * @param string uni + * + */ +export function orderAgain(uni) { + return request.post('order/again', { + uni: uni + }); +} + +/** + * 订单收货 + * @param string uni + * + */ +export function orderTake(uni) { + return request.post('order/take', { + uni: uni + }); +} + +/** + * 订单查询物流信息 + * @returns {*} + */ +export function express(uni, type) { + return request.get("order/express/" + uni + `${type?'/refund':''}`); +} +/** + * 订单查询物流信息 + * @returns {*} + */ +export function adminExpress(uni, type) { + return request.get("admin/order/express/" + uni + `${type?'/refund':''}`); +} + +/** + * 获取退款理由 + * + */ +export function ordeRefundReason() { + return request.get('order/refund/reason'); +} + +/** + * 订单退款审核 + * @param object data + */ +export function orderRefundVerify(data) { + return request.post('order/refund/verify', data); +} + +/** + * 订单确认获取订单详细信息 + * @param string cartId + */ +export function orderConfirm(cartId, news, addressId, shipping_type) { + return request.post('order/confirm', { + cartId, + 'new': news, + addressId, + shipping_type + }); +} + +/** + * 获取确认订单页面是否展示快递配送和到店自提 + * @param string cartId + */ +export function checkShipping(cartId, news) { + return request.post('order/check_shipping', { + cartId, + 'new': news + }); +} + +/** + * 获取当前金额能使用的优惠卷 + * @param string price + * + */ +export function getCouponsOrderPrice(price, data) { + return request.get('coupons/order/' + price, data) +} + +/** + * 订单创建 + * @param string key + * @param object data + * + */ +export function orderCreate(key, data) { + return request.post('order/create/' + key, data); +} + +/** + * 计算订单金额 + * @param key + * @param data + * @returns {*} + */ +export function postOrderComputed(key, data) { + return request.post("order/computed/" + key, data); +} + +/** + * 订单优惠券 + * @param key + * @param data + * @returns {*} + */ +export function orderCoupon(orderId) { + return request.post("v2/order/product_coupon/" + orderId); +} + +/** + * 计算会员线下付款金额 + * @param {Object} data + */ +export function offlineCheckPrice(data) { + return request.post("order/offline/check/price", data); +} + +/** + * 线下扫码付款 + * @param {Object} data + */ +export function offlineCreate(data) { + return request.post("order/offline/create", data); +} + +/** + * 支付方式开关 + */ +export function orderOfflinePayType() { + return request.get('order/offline/pay/type'); +} + +/** + * 开票记录 + */ +export function orderInvoiceList(data) { + return request.get('v2/order/invoice_list', data); +} + +/** + * 开票订单详情 + * @param {Object} id + */ +export function orderInvoiceDetail(id) { + return request.get(`v2/order/invoice_detail/${id}`); +} + + +/** + * 支付宝支付 + * @param {Object} key + * @param {Object} quitUrl + */ +export function aliPay(key, quitUrl) { + return request.get('ali_pay', { + key, + quitUrl + }, { + noAuth: true + }); +} + + +/** + * 退货物流单号提交 + * @param {Object} data + */ +export function refundExpress(data) { + return request.post("order/refund/express", data); +} + +/** + * 分类购物车列表 + */ +export function vcartList() { + return request.get("v2/cart_list"); +} + +/** + * 退款商品列表 + */ +export function refundGoodsList(orderId) { + return request.get(`order/refund/cart_info/${orderId}`); +} + +/** + * 申请退款商品列表 + */ +export function postRefundGoods(data) { + return request.post(`order/refund/cart_info`, data); +} + +/** + * 退款商品提交 + */ +export function returnGoodsSubmit(id, data) { + return request.post(`order/refund/apply/${id}`, data); +} + +/** + * 新订单列表 2.1版本 + * @param object data + */ +export function getNewOrderList(data) { + return request.get('order/refund/list', data); +} + +/** + * 退款订单详情 + * @param string uni + */ +export function refundOrderDetail(uni) { + return request.get('order/refund/detail/' + uni); +} + +/** + * 放弃申请退款 + * @param string uni + */ +export function cancelRefundOrder(uni) { + return request.post('order/refund/cancel/' + uni); +} + +/** + * 收银台订单信息 + * @param object data + */ +export function getCashierOrder(orderId, type) { + return request.get(`/api/order/cashier/${orderId}/${type}`); +} + +/** + * 发票地址获取 + * @param object data + */ +export function getInvoiceLink(id) { + return request.get(`v2/order/down_invoice/${id}`); +} + + +/** + * 点餐取消订单 + * @param string data + */ +export function cancelShopOrder(data) { + return request.post('merchant_order/order/cancelOrder', data); +} + +// /** +// * 线上商品取消订单 +// * @param string data +// */ +// export function cancelonlineOrder(data) { +// return request.post('/mall/api/cancel_order', data); +// } + + +/** + * 点餐扫码订单详情 + * @param string data + */ + +export function getOrderShopDetail(id) { + return request.get(`merchant/getOrderDetail?id=${id}`); +} + +/** + * 线上订单详情 + * @param string data + */ + +export function getonlineOrderDetail(id) { + return request.get(`order/detail/${id}`); +} +/** + * 充值订单详情 + * @param string data + */ +export function RechargeOrderDetail(id) { + return request.get(`virtual/orderDetail?id=${id}`); +} +/** + * 充值订单取消 + */ +export function RechargeorderCancel(data) { + return request.post('virtual/cancelOrder', data); +} + +/** + * 获取订单顶部Tabs + */ +export function OrderTabs(data) { + return request.get('order_tab_config', data); +} \ No newline at end of file diff --git a/api/public.js b/api/public.js new file mode 100644 index 0000000..dc46015 --- /dev/null +++ b/api/public.js @@ -0,0 +1,11 @@ +import request from "@/utils/request.js"; + +/** + * 配置信息 + * + */ +export function basicConfig(name) { + return request.get(`/api/basic_config`, {}, { + noAuth: true + }); +} \ No newline at end of file diff --git a/components/OnlineShop.vue b/components/OnlineShop.vue new file mode 100644 index 0000000..342b4e7 --- /dev/null +++ b/components/OnlineShop.vue @@ -0,0 +1,573 @@ + + + + + + + \ No newline at end of file diff --git a/components/countDown/index.vue b/components/countDown/index.vue new file mode 100644 index 0000000..b0e6e12 --- /dev/null +++ b/components/countDown/index.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/components/mono-keyboard/mono-keyboard.vue b/components/mono-keyboard/mono-keyboard.vue new file mode 100644 index 0000000..e95f4d7 --- /dev/null +++ b/components/mono-keyboard/mono-keyboard.vue @@ -0,0 +1,223 @@ + + + \ No newline at end of file diff --git a/components/numberScroll.vue b/components/numberScroll.vue new file mode 100644 index 0000000..2ace75d --- /dev/null +++ b/components/numberScroll.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/config/app.js b/config/app.js new file mode 100644 index 0000000..b18ec30 --- /dev/null +++ b/config/app.js @@ -0,0 +1,11 @@ +module.exports = { + HTTP_REQUEST_URL: 'https://point.agrimedia.cn', + HEADER: {}, + TOKENNAME: 'Authori-zation', + // 缓存时间 0 永久 + EXPIRE: 0, + //分页最多显示条数 + LIMIT: 10, + // 请求超时限制 默认10秒 + TIMEOUT: 10000 +} diff --git a/config/cache.js b/config/cache.js new file mode 100644 index 0000000..187ecb4 --- /dev/null +++ b/config/cache.js @@ -0,0 +1,46 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +module.exports = { + //token + LOGIN_STATUS: 'LOGIN_STATUS_TOKEN', + ISPAY: '', + //uid + UID:'UID', + //用户信息 + USER_INFO: 'USER_INFO', + //token过期时间 + EXPIRES_TIME: 'EXPIRES_TIME', + //微信登录 + WX_AUTH: 'WX_AUTH', + //公众号登录code + STATE_KEY: 'wx_authorize_state', + //登录类型 + LOGINTYPE: 'loginType', + //登录跳转地址 + BACK_URL: 'login_back_url', + //小程序登录状态code + STATE_R_KEY: 'roution_authorize_state', + //logo 地址 + LOGO_URL: 'LOGO_URL', + //模板缓存 + SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE', + + TIPS_KEY: 'TIPS_KEY', + + SPREAD: 'spread', + //缓存经度 + CACHE_LONGITUDE: 'LONGITUDE', + //缓存纬度 + CACHE_LATITUDE: 'LATITUDE', + + // 店铺信息 + USER_ADDRESS: 'USER_ADDRESS' +} diff --git a/config/payChat.js b/config/payChat.js new file mode 100644 index 0000000..9234ac5 --- /dev/null +++ b/config/payChat.js @@ -0,0 +1,35 @@ +import store from '@/store/index.js'; +import { HTTP_REQUEST_URL } from '@/config/app'; +import { getMerchantInfo } from '@/api/user.js'; + +/** + * 使用方式: + * 进入半屏小程序所需的参数 + * parameter: { + need_login: 1, + shop_id: 1 + } +*/ + +const PayParams = function(parameter) { + return getMerchantInfo(parameter.shop_id).then(res => { + let shopData = res.data; + + return { + name: shopData.name, + code: res.data.bar_code, + need_login: parameter.need_login, + shop_id: parameter.shop_id, + price: parameter.price, + isVip: parameter.isVip, + envVersion: parameter.envVersion, + + status: parameter.status, + token: parameter.token, + BASE_URL: HTTP_REQUEST_URL, + REQUEST_URL: parameter.REQUEST_URL, + }; + }); +}; + +export default PayParams; \ No newline at end of file diff --git a/config/socket.js b/config/socket.js new file mode 100644 index 0000000..7ac0205 --- /dev/null +++ b/config/socket.js @@ -0,0 +1,18 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +module.exports = { + // Socket链接 暂不做配置 + WSS_SERVER_URL:'', + // Socket调试模式 + SERVER_DEBUG:true, + // 心跳间隔 + PINGINTERVAL:3000 +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..b5d330d --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..dae342d --- /dev/null +++ b/main.js @@ -0,0 +1,27 @@ +import App from './App' +import store from './store' +import util from 'utils/util' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' + +Vue.prototype.$util = util; +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + store, + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + return { + app + } +} +// #endif \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..cf0875a --- /dev/null +++ b/manifest.json @@ -0,0 +1,77 @@ +{ + "name" : "收银台支付", + "appid" : "__UNI__B05F7DA", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "2", + "h5" : { + "router" : { + "mode" : "history" + } + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..ec1f6d0 --- /dev/null +++ b/pages.json @@ -0,0 +1,27 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "向商家付款", + "enablePullDownRefresh": false, + "navigationStyle": "custom" + } + }, + { + "path": "pages/Paysuccessful/jxPaysuccessful", + "style": { + "navigationBarTitleText": "支付结果", + "enablePullDownRefresh": false, + "navigationStyle": "custom" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "uni-app", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "uniIdRouter": {} +} diff --git a/pages/Paysuccessful/jxPaysuccessful.vue b/pages/Paysuccessful/jxPaysuccessful.vue new file mode 100644 index 0000000..45b35fb --- /dev/null +++ b/pages/Paysuccessful/jxPaysuccessful.vue @@ -0,0 +1,189 @@ + + + + + \ No newline at end of file diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..4d5c19a --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,606 @@ + + + + + \ No newline at end of file diff --git a/static/css/pageElement.scss b/static/css/pageElement.scss new file mode 100755 index 0000000..048f72c --- /dev/null +++ b/static/css/pageElement.scss @@ -0,0 +1,16 @@ +#app { + max-width: 750rpx; + min-width: 750rpx; + height: auto; + margin: 0 auto; + min-height: 100%; +} + +page { + /* // background-color: #1C1C1E; + // background-image: url('https://img.agrimedia.cn/sch5/bg.png'); + // background-size: cover; */ + padding: 30.77rpx; + height: 100%; + width: 100; +} \ No newline at end of file diff --git a/static/fail.png b/static/fail.png new file mode 100755 index 0000000..c8dc1d3 Binary files /dev/null and b/static/fail.png differ diff --git a/static/icon/demo.css b/static/icon/demo.css new file mode 100755 index 0000000..a67054a --- /dev/null +++ b/static/icon/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/static/icon/demo_index.html b/static/icon/demo_index.html new file mode 100755 index 0000000..24eb3b3 --- /dev/null +++ b/static/icon/demo_index.html @@ -0,0 +1,257 @@ + + + + + iconfont Demo + + + + + + + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    对勾_块
    +
    &#xed1d;
    +
  • + +
  • + +
    警告
    +
    &#xeb65;
    +
  • + +
  • + +
    购物车满
    +
    &#xe600;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1669284444124') format('woff2'),
+       url('iconfont.woff?t=1669284444124') format('woff'),
+       url('iconfont.ttf?t=1669284444124') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 对勾_块 +
    +
    .icon-duigou_kuai +
    +
  • + +
  • + +
    + 警告 +
    +
    .icon-jinggao +
    +
  • + +
  • + +
    + 购物车满 +
    +
    .icon-gouwucheman +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    对勾_块
    +
    #icon-duigou_kuai
    +
  • + +
  • + +
    警告
    +
    #icon-jinggao
    +
  • + +
  • + +
    购物车满
    +
    #icon-gouwucheman
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/static/icon/iconfont.css b/static/icon/iconfont.css new file mode 100755 index 0000000..fc4ffdd --- /dev/null +++ b/static/icon/iconfont.css @@ -0,0 +1,27 @@ +@font-face { + font-family: "iconfont"; /* Project id 3770712 */ + src: url('iconfont.woff2?t=1669284444124') format('woff2'), + url('iconfont.woff?t=1669284444124') format('woff'), + url('iconfont.ttf?t=1669284444124') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-duigou_kuai:before { + content: "\ed1d"; +} + +.icon-jinggao:before { + content: "\eb65"; +} + +.icon-gouwucheman:before { + content: "\e600"; +} + diff --git a/static/icon/iconfont.js b/static/icon/iconfont.js new file mode 100755 index 0000000..439ddcf --- /dev/null +++ b/static/icon/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_3770712='',function(n){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,i,a,d,c,s=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_3770712,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),o()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(a=o,d=n.document,c=!1,r(),d.onreadystatechange=function(){"complete"==d.readyState&&(d.onreadystatechange=null,l())})}function l(){c||(c=!0,a())}function r(){try{d.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}l()}}(window); \ No newline at end of file diff --git a/static/icon/iconfont.json b/static/icon/iconfont.json new file mode 100755 index 0000000..8ec8bd7 --- /dev/null +++ b/static/icon/iconfont.json @@ -0,0 +1,30 @@ +{ + "id": "3770712", + "name": "no name", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "7954334", + "name": "对勾_块", + "font_class": "duigou_kuai", + "unicode": "ed1d", + "unicode_decimal": 60701 + }, + { + "icon_id": "3868273", + "name": "警告", + "font_class": "jinggao", + "unicode": "eb65", + "unicode_decimal": 60261 + }, + { + "icon_id": "5030", + "name": "购物车满", + "font_class": "gouwucheman", + "unicode": "e600", + "unicode_decimal": 58880 + } + ] +} diff --git a/static/icon/iconfont.ttf b/static/icon/iconfont.ttf new file mode 100755 index 0000000..92ac68d Binary files /dev/null and b/static/icon/iconfont.ttf differ diff --git a/static/icon/iconfont.woff b/static/icon/iconfont.woff new file mode 100755 index 0000000..759bf40 Binary files /dev/null and b/static/icon/iconfont.woff differ diff --git a/static/icon/iconfont.woff2 b/static/icon/iconfont.woff2 new file mode 100755 index 0000000..fcb2b61 Binary files /dev/null and b/static/icon/iconfont.woff2 differ diff --git a/static/js/appconfig.js b/static/js/appconfig.js new file mode 100755 index 0000000..b9c31da --- /dev/null +++ b/static/js/appconfig.js @@ -0,0 +1,5 @@ +import { createSSRApp } from "vue"; +const app = createSSRApp(App); +const globals = app.config.globalProperties; +// console.log(app,'globals'); +export {globals}; \ No newline at end of file diff --git a/static/js/indt.ts b/static/js/indt.ts new file mode 100755 index 0000000..3c567a6 --- /dev/null +++ b/static/js/indt.ts @@ -0,0 +1,214 @@ +import Request_ from '../../api/request'; + + +class _init { + + // 登录完成回调(包含处理完成用户携带数据) + UserLoginInitCollback = undefined; + userInfor = {}; + // 微信登录之后获取到 参数 + openid : String = ""; + session_key : string = ""; + // Wechat = {}; + // 支付宝登录之后获取到的参数 + Apple = { + access_token: "0", + alipay_user_id: "0", + auth_start: "0", + expires_in: 0, + re_expires_in: 0, + refresh_token: "", + user_id: "", + }; + code = ''; + pay_type : number = 0; + provider : "weixin" | "qq" | "sinaweibo" | "xiaomi" | "apple" | "univerify" = 'weixin'; + // 进入来源 Scan | Half + referrerInfo:'Scan' | 'Half'; + // 初始参数 + __programParameter__ = null; + /** 请求参数 */ + APIoptions = {}; + constructor(parameters) { + // #ifdef MP-ALIPAY + this['pay_type'] = 2; + // #endif + // #ifdef MP-WEIXIN + this['pay_type'] = 1; + // #endif + /** + * 初始化来源 + */ + // parameters.referrerInfo = { + // path:"pages/index/index", + // quer:{}, + // scene:1037, + // referrerInfo:{"appId":"wxc8e2e1d28d15d2e3"}, + // extraData:{ + // "thrust_code":"4871020984", + // code:"49750683" + // }, + // mode:"embedded", + // apiCategory:"embedded" + // }; + if(parameters?.referrerInfo && Object.keys(parameters['referrerInfo'])['length']){ + this.referrerInfo = 'Half'; + /** + * 初始化参数 + */ + this.__programParameter__ = parameters['referrerInfo']['extraData']; + this.APIoptions = this['__programParameter__']; + }else{ + this.referrerInfo = 'Scan'; + /** + * 初始化参数 + */ + this.__programParameter__ = parameters; + /**处理拿到的初始化参数 */ + this.InitParam(); + + }; + + + } + + /** 获取来源 */ + get source(){ + return this['referrerInfo']; + } + + + // 推送播报 + // Pushbroadcast(data){ + // if(getApp()['globalData']['Pay_Status'] == 2) return; + // Request_.GET({ url:"/MiniProgram/Order/cancelPaymentSound", data }); + // } + + Login() { + let url : string = null; + // #ifdef MP-ALIPAY + url = '/MiniProgram/Api/alipayCodeLogin'; + this['pay_type'] = 2; + // #endif + // #ifdef MP-WEIXIN + url = '/MiniProgram/Api/wechatCodeLogin'; + this['pay_type'] = 1; + console.log(uni.login,this['provider'],'执行登录'); + // #endif + uni.login({ + provider: this['provider'], + success: loginRes => { + console.log(loginRes['code'], 'code---'); + if (loginRes.code) { + let data = null; + // #ifdef MP-ALIPAY + console.log(loginRes['code'], 'apple:code'); + data = { code: loginRes['code'] }; + // #endif + + // #ifdef MP-WEIXIN + console.log(loginRes['code'], 'WeChat:code'); + data = { code: loginRes['code'], type: 1 }; + // #endif + data['thrust_code'] = this['options']['thrust_code'] || ''; + data['invite_code'] = this['options']['invite_code'] || ''; + // return + + console.log(data,'data') + this.userInfor = data; + Request_.GET({ url, data }).then(res => { + this.userInfor = {...this['userInfor'],...res['data']} + uni.setStorageSync('token', res['data']['token']); + console.log(res, '登录信息'); + // #ifdef MP-ALIPAY + // let { openid, session_key } = res['data']; + this['Apple'] = res['data']; + // #endif + // #ifdef MP-WEIXIN + let { scan_openid, session_key } = res['data']; + this['openid'] = scan_openid; + this['session_key'] = session_key; + // #endif + console.log(this['UserLoginInitCollback'], 'UserLoginInitCollback'); + if (this['UserLoginInitCollback'] != null && typeof this['UserLoginInitCollback'] == 'function') { + this.UserLoginInitCollback(); + } + }) + } else { + uni.showToast({ + title: '登录失败!未获取到code', + icon: 'none', + duration: 2000 + }) + } + }, + fail:error=>{ + console.log(error,'error') + } + }); + } + + // 支付时获取指定平台字段 + get Getopenid() { + // #ifdef MP-ALIPAY + return this['Apple']['user_id']; + // #endif + // #ifdef MP-WEIXIN + return this['openid']; + // #endif + } + + get options(){ + return this['APIoptions'] + } + + // 解析小程序初始参数 + InitParam() { + console.log(this['__programParameter__'],this['source'],'__programParameter__'); + // 扫码进入 + if (this['__programParameter__']?.query?.q || this['__programParameter__']?.query?.scene || this['__programParameter__']?.query?.qrCode) { + let searchParamToObj = ''; + searchParamToObj = this['__programParameter__']['query']?.q || this['__programParameter__']['query']?.scene || this['__programParameter__']['query']?.qrCode; + console.log(searchParamToObj, 'searchParamToObj'); + const obj = {}; + const Para = this.escape2Html(decodeURIComponent(searchParamToObj)); + const _i = Para.indexOf('?'); + console.log(Para, _i, 'Para'); + if (~_i) { + const _U = Para.slice(_i + 1, Para['length']); + const _M = _U.split('&'); + + for (let i = 0; i < _M['length']; i++) { + const index = _M[i].indexOf("="); + console.log(index, 'index'); + const KEY = _M[i].substring(0, index); + const VAL = _M[i].substring(index + 1, _M[i].length); + obj[KEY] = VAL; + }; + this.APIoptions = obj; + + } else { + this.APIoptions = {}; + } + } else { + // 商户端扫码进入 + try{ + this.APIoptions = this['__programParameter__']['query']; + }catch(e){ + this.APIoptions = {}; + //TODO handle the exception + } + } + + } + + // 字符转义 + escape2Html(str) { + var arrEntities = { 'lt': '<', 'gt': '>', 'nbsp': ' ', 'amp': '&', 'quot': '"' }; + return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function (all, t) { return arrEntities[t]; }); + }; + +} + + +export default _init; \ No newline at end of file diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/static/logo.png differ diff --git a/static/mono-keyboard/backspace.png b/static/mono-keyboard/backspace.png new file mode 100644 index 0000000..ee1ee32 Binary files /dev/null and b/static/mono-keyboard/backspace.png differ diff --git a/static/mono-keyboard/backspace_dark.png b/static/mono-keyboard/backspace_dark.png new file mode 100644 index 0000000..6cf0e42 Binary files /dev/null and b/static/mono-keyboard/backspace_dark.png differ diff --git a/static/success.png b/static/success.png new file mode 100755 index 0000000..23db6f6 Binary files /dev/null and b/static/success.png differ diff --git a/store/getters.js b/store/getters.js new file mode 100644 index 0000000..6f2c885 --- /dev/null +++ b/store/getters.js @@ -0,0 +1,28 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +export default { + token: state => state.app.token, + isLogin: state => !!state.app.token, + backgroundColor: state => state.app.backgroundColor, + userInfo: state => state.app.userInfo || {}, + uid: state => state.app.uid, + homeActive: state => state.app.homeActive, + home: state => state.app.home, + cartNum: state => state.indexData.cartNum, + activityTab: state => state.app.activityTab, + address: state => state.app.addressInfo +}; +// export default { +// token: state => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJrYWlmYS5jcm1lYi5uZXQiLCJhdWQiOiJrYWlmYS5jcm1lYi5uZXQiLCJpYXQiOjE1NzcwODM1MzQsIm5iZiI6MTU3NzA4MzUzNCwiZXhwIjoxNTc3MDk0MzM0LCJqdGkiOnsiaWQiOjExMCwidHlwZSI6InVzZXIifX0.U-i1pbdRjyXI1gr79Uq2XBPZ89T8f5Ai9jwrR8woTwE', +// isLogin: state => true, +// backgroundColor: state => state.app.backgroundColor, +// userInfo: state => state.app.userInfo || {} +// }; \ No newline at end of file diff --git a/store/index.js b/store/index.js new file mode 100644 index 0000000..ce3da58 --- /dev/null +++ b/store/index.js @@ -0,0 +1,23 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +import Vue from "vue"; +import Vuex from "vuex"; +import modules from "./modules"; +import getters from "./getters"; + +Vue.use(Vuex); +const debug = process.env.NODE_ENV !== "production"; + +export default new Vuex.Store({ + modules, + getters, + strict: debug +}); diff --git a/store/modules/app.js b/store/modules/app.js new file mode 100644 index 0000000..9e0c2b6 --- /dev/null +++ b/store/modules/app.js @@ -0,0 +1,37 @@ + +import { + LOGIN_STATUS, + ISPAY, + UID, + USER_INFO, + USER_ADDRESS +} from '../../config/cache'; +import Cache from '../../utils/cache'; + +const state = { + token: Cache.get(LOGIN_STATUS) || false, + ISPAY: Cache.get(ISPAY) || '', +}; + +const mutations = { + LOGIN(state, opt) { + state.token = opt.token; + }, + UPDATE_LOGIN(state, token) { + state.token = token; + Cache.set(LOGIN_STATUS, token); + }, + SETALL_PAT(state, data) { + state.ISPAY = data; + Cache.set(ISPAY, data); + } +}; + +const actions = { +}; + +export default { + state, + mutations, + actions +}; diff --git a/store/modules/index.js b/store/modules/index.js new file mode 100644 index 0000000..e46e951 --- /dev/null +++ b/store/modules/index.js @@ -0,0 +1,14 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +import app from "./app"; +export default { + app, +}; diff --git a/uni.promisify.adaptor.js b/uni.promisify.adaptor.js new file mode 100644 index 0000000..5fec4f3 --- /dev/null +++ b/uni.promisify.adaptor.js @@ -0,0 +1,13 @@ +uni.addInterceptor({ + returnValue (res) { + if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { + return res; + } + return new Promise((resolve, reject) => { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..62eb87b --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/utils/cache.js b/utils/cache.js new file mode 100644 index 0000000..634edb9 --- /dev/null +++ b/utils/cache.js @@ -0,0 +1,230 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +import { + EXPIRE +} from '../config/app'; + +class Cache { + + constructor(handler) { + this.cacheSetHandler = uni.setStorageSync; + this.cacheGetHandler = uni.getStorageSync; + this.cacheClearHandler = uni.removeStorageSync; + this.cacheExpire = 'UNI-APP-CRMEB:TAG'; + this.clearOverdue(); + } + + /** + * 获取当前时间戳 + */ + time() { + return Math.round(new Date() / 1000); + } + + /** + * 字符串转时间戳 + * @param {Object} expiresTime + */ + strTotime(expiresTime) { + let expires_time = expiresTime.substring(0, 19); + expires_time = expires_time.replace(/-/g, '/'); + return Math.round(new Date(expires_time).getTime() / 1000); + } + + + /** + * 设置过期时间缓存 + * @param {Object} key + * @param {Object} expire + */ + setExpireCaheTag(key, expire) { + expire = expire !== undefined ? expire : EXPIRE; + if (typeof expire === 'number') { + let tag = this.cacheGetHandler(this.cacheExpire), + newTag = [], + newKeys = []; + if (typeof tag === 'object' && tag.length) { + newTag = tag.map(item => { + newKeys.push(item.key); + if (item.key === key) { + item.expire = expire === 0 ? 0 : this.time() + expire; + } + return item; + }); + } + if (!newKeys.length || newKeys.indexOf(key) === -1) { + newTag.push({ + key: key, + expire: expire === 0 ? 0 : this.time() + expire + }); + } + this.cacheSetHandler(this.cacheExpire, newTag); + } + } + + /** + * 缓存是否过期,过期自动删除 + * @param {Object} key + * @param {Object} $bool true = 删除,false = 不删除 + */ + getExpireCahe(key, $bool) { + try { + let tag = this.cacheGetHandler(this.cacheExpire), + time = 0, + index = false; + if (typeof tag === 'object' && tag.length) { + tag.map((item, i) => { + if (item.key === key) { + time = item.expire + index = i + } + }); + if (time) { + let newTime = parseInt(time); + if (time && time < this.time() && !Number.isNaN(newTime)) { + if ($bool === undefined || $bool === true) { + this.cacheClearHandler(key); + if (index !== false) { + tag.splice(index, 1) + this.cacheSetHandler(this.cacheExpire, tag); + } + } + return false; + } else + return true; + } else { + return !!this.cacheGetHandler(key); + } + } + return false; + } catch (e) { + return false; + } + } + + /** + * 设置缓存 + * @param {Object} key + * @param {Object} data + */ + set(key, data, expire) { + if (data === undefined) { + return true; + } + if (typeof data === 'object') + data = JSON.stringify(data); + try { + this.setExpireCaheTag(key, expire); + return this.cacheSetHandler(key, data); + } catch (e) { + return false; + } + } + + /** + * 检测缓存是否存在 + * @param {Object} key + */ + has(checkwhethethecacheexists, isDel) { + this.clearOverdue(); + return this.getExpireCahe(checkwhethethecacheexists, isDel); + } + + /** + * 获取缓存 + * @param {Object} key + * @param {Object} $default + * @param {Object} expire + */ + get(key, $default, expire) { + this.clearOverdue(); + try { + let isBe = this.getExpireCahe(key); + let data = this.cacheGetHandler(key); + if (data && isBe) { + if (typeof $default === 'boolean') + return JSON.parse(data); + else + return data; + } else { + if (typeof $default === 'function') { + let value = $default(); + this.set(key, value, expire); + return value; + } else { + this.set(key, $default, expire); + return $default; + } + } + } catch (e) { + return null; + } + } + + /** + * 删除缓存 + * @param {Object} key + */ + clear(key) { + try { + let cahceValue = this.cacheGetHandler(this.cacheExpire), + index = false; + if (cahceValue && typeof cahceValue === 'object' && cahceValue.length) { + cahceValue.map((item, i) => { + if (item.key === key) { + index = i; + } + }); + + if (index !== false) { + cahceValue.splice(index, 1); + } + this.cacheSetHandler(this.cacheExpire, cahceValue); + } + return this.cacheClearHandler(key); + } catch (e) { + return false; + } + } + + /** + * 清除过期缓存 + */ + clearOverdue() { + let cahceValue = this.cacheGetHandler(this.cacheExpire), + time = this.time(), + newBeOverdueValue = [], + newTagValue = []; + + if (cahceValue && typeof cahceValue === 'object' && cahceValue.length) { + cahceValue.map(item => { + if (item) { + if ((item.expire !== undefined && item.expire > time) || item.expire === 0) { + newTagValue.push(item); + } else { + newBeOverdueValue.push(item.key); + } + } + }); + } + //保存没有过期的缓存标签 + if (newTagValue.length !== cahceValue.length) { + this.cacheSetHandler(this.cacheExpire, newTagValue); + } + //删除过期缓存 + newBeOverdueValue.forEach(k => { + this.cacheClearHandler(k); + }) + } +} + + +export default new Cache; diff --git a/utils/request.js b/utils/request.js new file mode 100644 index 0000000..282b9e2 --- /dev/null +++ b/utils/request.js @@ -0,0 +1,87 @@ +import { + HTTP_REQUEST_URL, + HEADER, + TOKENNAME, + TIMEOUT +} from '@/config/app'; +import store from '../store'; +import UrlUtils from './urlUtils.js'; + +/** + * 发送请求 + */ +function baseRequest(url, method, data, { + noAuth = false, + noVerify = false +}) { + let Url = HTTP_REQUEST_URL; + let header = HEADER; + + HEADER['form-type'] = 'gzh'; + header = HEADER; + + + if (store.state.app.token) header[TOKENNAME] = 'Bearer ' + store.state.app.token; + return new Promise((reslove, reject) => { + if (uni.getStorageSync('locale')) { + header['Cb-lang'] = uni.getStorageSync('locale') + } + uni.request({ + url: url, + method: method || 'GET', + header: header, + data: data || {}, + timeout: TIMEOUT, + success: (res) => { + if (noVerify) + reslove(res.data, res); + else if (res.data.status == 200) + reslove(res.data, res); + else if ([110002, 110003, 110004].indexOf(res.data.status) !== -1) { + // #ifdef H5 + window.location.replace(`${HTTP_REQUEST_URL}/api/v2/routine/gzhLogin?back_url=${encodeURIComponent(UrlUtils.keepParams(window.location.href))}`); + // #endif + + reject(res.data); + } else if (res.data.status == 400 && res.data.msg !== '商户未绑定码牌') { + uni.showToast({ + title: res.data.msg, + icon: 'error' + }) + reject(res.data.msg || '系统错误'); + } else if (res.data.status == 100103) { + uni.showModal({ + title: '提示', + content: res.data.msg, + showCancel: false, + confirmText: 我知道了 + }); + } else + reject(res.data.msg || '系统错误'); + }, + fail: (msg) => { + console.log(msg) + let data = { + mag: '请求失败1', + status: 1 //1没网 + } + // #ifdef APP-PLUS + reject(data); + // #endif + // #ifndef APP-PLUS + reject('请求失败'); + // #endif + } + }) + }); +} + +const request = {}; + +['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => { + request[method] = (api, data, opt) => baseRequest(api, method, data, opt || {}) +}); + + + +export default request; \ No newline at end of file diff --git a/utils/urlUtils.js b/utils/urlUtils.js new file mode 100644 index 0000000..ecfe894 --- /dev/null +++ b/utils/urlUtils.js @@ -0,0 +1,77 @@ +const UrlUtils = { + /** + * 清理URL(合并多余的?,规范参数分隔符) + * @param {string} url - 原始URL + * @returns {string} 清理后的URL + */ + clean: function(url) { + let cleanUrl = url.replace(/\?+/g, '?'); + const firstQuestionMarkIndex = cleanUrl.indexOf('?'); + + if (firstQuestionMarkIndex !== -1) { + const beforeParams = cleanUrl.substring(0, firstQuestionMarkIndex + 1); + const afterParams = cleanUrl.substring(firstQuestionMarkIndex + 1).replace(/\?/g, '&'); + cleanUrl = beforeParams + afterParams; + } + + return cleanUrl; + }, + + /** + * 保留URL中指定的参数(默认只保留merchant_id) + * @param {string} url - 原始URL + * @param {string[]} [paramsToKeep=['merchant_id']] - 需要保留的参数名数组 + * @returns {string} 简化后的URL + */ + keepParams: function(url, paramsToKeep = ['merchant_id']) { + // 先清理URL + const cleanedUrl = this.clean(url); + + try { + const urlObj = new URL(cleanedUrl); + const newSearchParams = new URLSearchParams(); + + // 遍历原始参数,只保留需要的 + urlObj.searchParams.forEach((value, key) => { + if (paramsToKeep.includes(key)) { + newSearchParams.append(key, value); + } + }); + + // 重建URL + urlObj.search = newSearchParams.toString(); + return urlObj.toString(); + } catch (e) { + // 如果URL解析失败(如缺少协议),回退到字符串处理 + const [basePart, queryPart] = cleanedUrl.split('?'); + if (!queryPart) return basePart; + + const keptParams = queryPart.split('&').filter(param => { + const [key] = param.split('='); + return paramsToKeep.includes(key); + }); + + return keptParams.length > 0 + ? `${basePart}?${keptParams.join('&')}` + : basePart; + } + } +}; + +export default UrlUtils + + +// // 使用示例 +// const dirtyUrl = "http://10.210.254.149:8081/h5_pay/??merchant_id=1&token=xxx&expires_time=123??is_all_api=1"; + +// // 1. 只清理URL +// console.log(UrlUtils.clean(dirtyUrl)); +// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1&token=xxx&expires_time=123&is_all_api=1" + +// // 2. 清理并只保留merchant_id +// console.log(UrlUtils.keepParams(dirtyUrl)); +// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1" + +// // 3. 清理并保留多个参数 +// console.log(UrlUtils.keepParams(dirtyUrl, ['merchant_id', 'expires_time'])); +// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1&expires_time=123" diff --git a/utils/util.js b/utils/util.js new file mode 100644 index 0000000..8871b34 --- /dev/null +++ b/utils/util.js @@ -0,0 +1,1278 @@ +// +---------------------------------------------------------------------- +// | CRMEB [ CRMEB赋能开发者,助力企业发展 ] +// +---------------------------------------------------------------------- +// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved. +// +---------------------------------------------------------------------- +// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 +// +---------------------------------------------------------------------- +// | Author: CRMEB Team +// +---------------------------------------------------------------------- + +export default { + /** + * opt object | string + * to_url object | string + * 例: + * this.Tips('/pages/test/test'); 跳转不提示 + * this.Tips({title:'提示'},'/pages/test/test'); 提示并跳转 + * this.Tips({title:'提示'},{tab:1,url:'/pages/index/index'}); 提示并跳转值table上 + * tab=1 一定时间后跳转至 table上 + * tab=2 一定时间后跳转至非 table上 + * tab=3 一定时间后返回上页面 + * tab=4 关闭所有页面,打开到应用内的某个页面 + * tab=5 关闭当前页面,跳转到应用内的某个页面 + */ + Tips: function(opt, to_url) { + if (typeof opt == 'string') { + to_url = opt; + opt = {}; + } + let title = opt.title || '', + icon = opt.icon || 'none', + endtime = opt.endtime || 2000, + success = opt.success; + if (title) uni.showToast({ + title: title, + icon: icon, + duration: endtime, + success + }) + if (to_url != undefined) { + if (typeof to_url == 'object') { + let tab = to_url.tab || 1, + url = to_url.url || ''; + switch (tab) { + case 1: + //一定时间后跳转至 table + setTimeout(function() { + uni.switchTab({ + url: url + }) + }, endtime); + break; + case 2: + //跳转至非table页面 + setTimeout(function() { + uni.navigateTo({ + url: url, + }) + }, endtime); + break; + case 3: + //返回上页面 + setTimeout(function() { + // #ifndef H5 + uni.navigateBack({ + delta: parseInt(url), + }) + // #endif + // #ifdef H5 + history.back(); + // #endif + }, endtime); + break; + case 4: + //关闭所有页面,打开到应用内的某个页面 + setTimeout(function() { + uni.reLaunch({ + url: url, + }) + }, endtime); + break; + case 5: + //关闭当前页面,跳转到应用内的某个页面 + setTimeout(function() { + uni.redirectTo({ + url: url, + }) + }, endtime); + break; + } + + } else if (typeof to_url == 'function') { + setTimeout(function() { + to_url && to_url(); + }, endtime); + } else { + //没有提示时跳转不延迟 + setTimeout(function() { + uni.navigateTo({ + url: to_url, + }) + }, title ? endtime : 0); + } + } + }, + /** + * 移除数组中的某个数组并组成新的数组返回 + * @param array array 需要移除的数组 + * @param int index 需要移除的数组的键值 + * @param string | int 值 + * @return array + * + */ + ArrayRemove: function(array, index, value) { + const valueArray = []; + if (array instanceof Array) { + for (let i = 0; i < array.length; i++) { + if (typeof index == 'number' && array[index] != i) { + valueArray.push(array[i]); + } else if (typeof index == 'string' && array[i][index] != value) { + valueArray.push(array[i]); + } + } + } + return valueArray; + }, + /** + * 生成海报获取文字 + * @param string text 为传入的文本 + * @param int num 为单行显示的字节长度 + * @return array + */ + textByteLength: function(text, num) { + let strLength = 0; + let rows = 1; + let str = 0; + let arr = []; + for (let j = 0; j < text.length; j++) { + if (text.charCodeAt(j) > 255) { + strLength += 2; + if (strLength > rows * num) { + strLength++; + arr.push(text.slice(str, j)); + str = j; + rows++; + } + } else { + strLength++; + if (strLength > rows * num) { + arr.push(text.slice(str, j)); + str = j; + rows++; + } + } + } + arr.push(text.slice(str, text.length)); + return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数] + }, + + /** + * 获取分享海报 + * @param array arr2 海报素材 + * @param string store_name 素材文字 + * @param string price 价格 + * @param string ot_price 原始价格 + * @param function successFn 回调函数 + * + * + */ + PosterCanvas: function(arr2, store_name, price, ot_price, successFn) { + let that = this; + uni.showLoading({ + title: i18n.t(`海报生成中`), + mask: true + }); + const ctx = uni.createCanvasContext('myCanvas'); + ctx.clearRect(0, 0, 0, 0); + + + /** + * 只能获取合法域名下的图片信息,本地调试无法获取 + * + */ + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, 750, 1250); + uni.getImageInfo({ + src: arr2[0], + success: function(res) { + const WIDTH = res.width; + const HEIGHT = res.height; + // ctx.drawImage(arr2[0], 0, 0, WIDTH, 1050); + ctx.drawImage(arr2[1], 0, 0, WIDTH, WIDTH); + ctx.save(); + let r = 110; + let d = r * 2; + let cx = 480; + let cy = 790; + ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI); + // ctx.clip(); + ctx.drawImage(arr2[2], cx, cy, d, d); + ctx.restore(); + const CONTENT_ROW_LENGTH = 20; + let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name, + CONTENT_ROW_LENGTH); + if (contentRows > 2) { + contentRows = 2; + let textArray = contentArray.slice(0, 2); + textArray[textArray.length - 1] += '……'; + contentArray = textArray; + } + ctx.setTextAlign('left'); + ctx.setFontSize(36); + ctx.setFillStyle('#000'); + // let contentHh = 36 * 1.5; + let contentHh = 36; + for (let m = 0; m < contentArray.length; m++) { + if (m) { + ctx.fillText(contentArray[m], 50, 1000 + contentHh * m + 18, 1100); + } else { + ctx.fillText(contentArray[m], 50, 1000 + contentHh * m, 1100); + } + } + ctx.setTextAlign('left') + ctx.setFontSize(72); + ctx.setFillStyle('#DA4F2A'); + ctx.fillText(i18n.t(`¥`) + price, 40, 820 + contentHh); + + ctx.setTextAlign('left') + ctx.setFontSize(36); + ctx.setFillStyle('#999'); + + if (ot_price) { + ctx.fillText(i18n.t(`¥`) + ot_price, 50, 876 + contentHh); + var underline = function(ctx, text, x, y, size, color, thickness, offset) { + var width = ctx.measureText(text).width; + switch (ctx.textAlign) { + case "center": + x -= (width / 2); + break; + case "right": + x -= width; + break; + } + + y += size + offset; + + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = thickness; + ctx.moveTo(x, y); + ctx.lineTo(x + width, y); + ctx.stroke(); + } + underline(ctx, i18n.t(`¥`) + ot_price, 55, 865, 36, '#999', 2, 0) + } + ctx.setTextAlign('left') + ctx.setFontSize(28); + ctx.setFillStyle('#999'); + ctx.fillText(i18n.t(`长按或扫描查看`), 490, 1030 + contentHh); + ctx.draw(true, function() { + uni.canvasToTempFilePath({ + canvasId: 'myCanvas', + fileType: 'png', + destWidth: WIDTH, + destHeight: HEIGHT, + success: function(res) { + uni.hideLoading(); + successFn && successFn(res.tempFilePath); + } + }) + }); + }, + fail: function(err) { + uni.hideLoading(); + that.Tips({ + title: i18n.t(`无法获取图片信息`) + }); + } + }) + }, + /** + * 获取砍价/拼团海报 + * @param array arr2 海报素材 背景图 + * @param string store_name 素材文字 + * @param string price 价格 + * @param string ot_price 原始价格 + * @param function successFn 回调函数 + * + * + */ + bargainPosterCanvas: function(arr2, title, label, msg, price, wd, hg, successFn) { + let that = this; + const ctx = uni.createCanvasContext('myCanvas'); + ctx.clearRect(0, 0, 0, 0); + /** + * 只能获取合法域名下的图片信息,本地调试无法获取 + * + */ + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, wd * 2, hg * 2); + uni.getImageInfo({ + src: arr2[0], + success: function(res) { + const WIDTH = res.width; + const HEIGHT = res.height; + ctx.drawImage(arr2[0], 0, 0, wd, hg); + + // 保证在不同机型对应坐标准确 + let labelx = 0.6500 //标签x + let labely = 0.166 //标签y + let pricex = 0.1857 //价格x + let pricey = 0.180 //价格x + let codex = 0.385 //二维码 + let codey = 0.77 + let picturex = 0.1571 //商品图左上点 + let picturey = 0.2916 + let picturebx = 0.6857 //商品图右下点 + let pictureby = 0.4316 + let msgx = 0.1036 //msg + let msgy = 0.2306 + let codew = 0.25 + ctx.drawImage(arr2[1], wd * picturex, hg * picturey, wd * picturebx, hg * pictureby); + ctx.drawImage(arr2[2], wd * codex, hg * codey, wd * codew, wd * codew); + ctx.save(); + //标题 + const CONTENT_ROW_LENGTH = 32; + let [contentLeng, contentArray, contentRows] = that.textByteLength(title, + CONTENT_ROW_LENGTH); + if (contentRows > 2) { + contentRows = 2; + let textArray = contentArray.slice(0, 2); + textArray[textArray.length - 1] += '…'; + contentArray = textArray; + } + ctx.setTextAlign('left'); + ctx.setFillStyle('#000'); + if (contentArray.length < 2) { + ctx.setFontSize(22); + } else { + ctx.setFontSize(20); + } + let contentHh = 8; + for (let m = 0; m < contentArray.length; m++) { + if (m) { + ctx.fillText(contentArray[m], 20, 35 + contentHh * m + 18, 1100); + } else { + ctx.fillText(contentArray[m], 20, 35, 1100); + } + } + // 标签内容 + ctx.setTextAlign('left') + ctx.setFontSize(16); + ctx.setFillStyle('#FFF'); + ctx.fillText(label, wd * labelx, hg * labely); + ctx.save(); + // 价格 + ctx.setFillStyle('red'); + ctx.setFontSize(26); + ctx.fillText(price, wd * pricex, hg * pricey); + ctx.save(); + // msg + ctx.setFillStyle('#333'); + ctx.setFontSize(16); + ctx.fillText(msg, wd * msgx, hg * msgy); + ctx.save(); + ctx.draw(true, () => { + uni.canvasToTempFilePath({ + canvasId: 'myCanvas', + fileType: 'png', + quality: 1, + success: (res) => { + successFn && successFn(res.tempFilePath); + uni.hideLoading(); + } + }) + }); + }, + fail: function(err) { + uni.hideLoading(); + that.Tips({ + title: i18n.t(`无法获取图片信息`) + }); + } + }) + }, + /** + * 用户信息分享海报 + * @param array arr2 海报素材 1背景 0二维码 + * @param string nickname 昵称 + * @param string sitename 价格 + * @param function successFn 回调函数 + * + * + */ + userPosterCanvas: function(arr2, nickname, sitename, index, w, h, uid, successFn) { + let that = this; + const ctx = uni.createCanvasContext('myCanvas' + index); + ctx.clearRect(0, 0, 0, 0); + /** + * 只能获取合法域名下的图片信息,本地调试无法获取 + * + */ + uni.getImageInfo({ + src: arr2[1], + success: function(res) { + const WIDTH = res.width; + const HEIGHT = res.height; + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, w, h); + ctx.drawImage(arr2[1], 0, 0, w, h); + ctx.setTextAlign('left') + ctx.setFontSize(12); + ctx.setFillStyle('#333'); + + // x:240 y:426 + let codex = 0.1906 + let codey = 0.7746 + let codeSize = 0.21666 + let namex = 0.4283 + let namey = 0.8215 + let markx = 0.4283 + let marky = 0.8685 + ctx.drawImage(arr2[0], w * codex, h * codey, w * codeSize, w * codeSize); + if (w < 270) { + ctx.setFontSize(8); + } else { + ctx.setFontSize(10); + } + ctx.fillText(nickname, w * namex, h * namey-5); + if (w < 270) { + ctx.setFontSize(8); + } else { + ctx.setFontSize(10); + } + console.log(w, markx, w * markx) + ctx.fillText(i18n.t(`邀请您加入`) + sitename, w * markx, h * marky-11); + ctx.fillText(i18n.t(`邀请码: ${uid}`), w * markx, h * marky+8); + ctx.save(); + ctx.draw(true, function() { + uni.canvasToTempFilePath({ + canvasId: 'myCanvas' + index, + fileType: 'png', + quality: 1, + success: function(res) { + successFn && successFn(res.tempFilePath); + } + }) + }); + }, + fail: function(err) { + console.log(err) + uni.hideLoading(); + that.Tips({ + title: i18n.t(`无法获取图片信息`) + }); + } + }) + }, + + /* + * 判断身份证是否过期 + */ + isIDCardExpired: function(validityPeriod, currentDate = new Date()) { + let that = this; + // 检查有效期格式是否正确 + if (!validityPeriod || !validityPeriod.includes('-')) { + that.Tips({ + title: '识别身份证有效期格式错误' + }); + } + + // 拆分有效期(起始日期和截止日期) + const [startDateStr, endDateStr] = validityPeriod.split('-'); + + // 解析日期字符串为 Date 对象 + const parseDate = (dateStr) => { + const year = parseInt(dateStr.slice(0, 4), 10); + const month = parseInt(dateStr.slice(4, 6), 10) - 1; // 月份从 0 开始 + const day = parseInt(dateStr.slice(6, 8), 10); + return new Date(year, month, day); + }; + + const startDate = parseDate(startDateStr); + const endDate = parseDate(endDateStr); + + // 检查当前日期是否在有效期内 + return currentDate > endDate || currentDate < startDate; + }, + + /* + * 单图上传 + * @param object opt + * @param callable successCallback 成功执行方法 data + * @param callable errorCallback 失败执行方法 + */ + uploadImageOne: function(opt, successCallback, errorCallback) { + let that = this; + if (typeof opt === 'string') { + let url = opt; + opt = {}; + opt.url = url; + } + let count = opt.count || 1, + sizeType = opt.sizeType || ['compressed'], + sourceType = opt.sourceType || ['album', 'camera'], + is_load = opt.is_load || true, + uploadUrl = opt.url || '', + inputName = opt.name || 'pics', + fileType = opt.fileType || 'image'; + uni.chooseImage({ + count: count, //最多可以选择的图片总数 + sizeType: sizeType, // 可以指定是原图还是压缩图,默认二者都有 + sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有 + success: function(res) { + //启动上传等待中... + uni.showLoading({ + title: i18n.t(`图片上传中`), + }); + uni.uploadFile({ + url: HTTP_REQUEST_URL + '/api/' + uploadUrl, + filePath: res.tempFilePaths[0], + fileType: fileType, + name: inputName, + formData: { + 'filename': inputName + }, + header: { + // #ifdef MP + "Content-Type": "multipart/form-data", + // #endif + [TOKENNAME]: 'Bearer ' + store.state.app.token + }, + success: function(res) { + uni.hideLoading(); + if (res.statusCode == 403) { + that.Tips({ + title: res.data + }); + } else { + let data = res.data ? JSON.parse(res.data) : {}; + if (data.status == 200) { + successCallback && successCallback(data) + } else { + errorCallback && errorCallback(data); + that.Tips({ + title: data.msg + }); + } + } + }, + fail: function(res) { + console.log(res) + uni.hideLoading(); + that.Tips({ + title: i18n.t(`上传图片失败`) + }); + } + }) + } + }) + }, + + compressImageToTargetSize: function(opt, successCallback, errorCallback, sizeCallback) { + let that = this; + if (typeof opt === 'string') { + let url = opt; + opt = {}; + opt.url = url; + } + let count = opt.count || 1, + sizeType = opt.sizeType || ['compressed'], + sourceType = opt.sourceType || ['album', 'camera'], + is_load = opt.is_load || true, + uploadUrl = opt.url || '', + inputName = opt.name || 'pics', + fileType = opt.fileType || 'image'; + uni.chooseImage({ + count: count, + sizeType: sizeType, + sourceType: sourceType, + success: function(res) { + //启动上传等待中... + const tempFilePaths = res.tempFilePaths[0]; // 获取到图片的临时路径 + uni.compressImage({ + src: tempFilePaths, + quality: 80, + success: res => { + uploadImg(res.tempFilePath) + } + }) + return + compress(tempFilePaths, 800, 600); // 调用压缩函数,指定宽度和高度 + }, + fail: function(res) { + var title = res.errMsg; + console.log(title, '111111111') + if (title == 'chooseImage:fail cancel') { + title = '取消选择照片' + } + + if (title == 'chooseImage:fail:systempermission denied') { + title = '请检查相册和相机权限' + } + + if (title == 'chooseImage:fail privacy permission is not authorized') { + title = '获取照片隐私权限失败' + } + + if (title == 'chooseImage:fail privacy permission is not authorized in gap') { + title = '获取照片隐私权限失败' + } + + that.Tips({ + title: title + }); + } + }) + + // 废弃 质量太低 + function compress(src, width, height) { + const that = this; + uni.getImageInfo({ + src: src, + success: function (infoRes) { + const { width: imgWidth, height: imgHeight } = infoRes; + const scale = Math.min(width / imgWidth, height / imgHeight); // 计算缩放比例 + const newWidth = imgWidth * scale; + const newHeight = imgHeight * scale; + const ctx = uni.createCanvasContext('myCanvas', that); // 创建canvas上下文 + ctx.drawImage(src, 0, 0, newWidth, newHeight); // 绘制图片到canvas上 + setTimeout(() => { + ctx.draw(true, () => { // 完成绘制后,导出图片 + uni.canvasToTempFilePath({ + canvasId: 'myCanvas', + success: function (res) { + console.log(res.tempFilePath) // 设置压缩后的图片路径 + uploadImg(res.tempFilePath) + }, + fail: function (err) { + console.error(err); + } + }); + }); + }, 1000) + } + }); + } + + function uploadImg(filePath) { + uni.uploadFile({ + url: HTTP_REQUEST_URL + '/api/' + uploadUrl, + filePath, + fileType: fileType, + name: inputName, + formData: { + 'filename': inputName + }, + header: { + // #ifdef MP + "Content-Type": "multipart/form-data", + // #endif + [TOKENNAME]: 'Bearer ' + store.state.app.token + }, + success: function(res) { + uni.hideLoading(); + if (res.statusCode == 403) { + that.Tips({ + title: res.data + }); + } else { + let data = res.data ? JSON.parse(res.data) : {}; + if (data.status == 200) { + successCallback && successCallback(data) + } else { + errorCallback && errorCallback(data); + that.Tips({ + title: data.msg + }); + } + } + }, + fail: function(res) { + console.log(res) + uni.hideLoading(); + that.Tips({ + title: i18n.t(`上传图片失败`) + }); + } + }) + } + }, + + /* + * 单图上传压缩版 + * @param object opt + * @param callable successCallback 成功执行方法 data + * @param callable errorCallback 失败执行方法 + */ + uploadImageChange: function(opt, successCallback, errorCallback, sizeCallback) { + let that = this; + if (typeof opt === 'string') { + let url = opt; + opt = {}; + opt.url = url; + } + let count = opt.count || 1, + sizeType = opt.sizeType || ['compressed'], + sourceType = opt.sourceType || ['album', 'camera'], + is_load = opt.is_load || true, + uploadUrl = opt.url || '', + inputName = opt.name || 'pics', + fileType = opt.fileType || 'image'; + uni.chooseImage({ + count: count, //最多可以选择的图片总数 + sizeType: sizeType, // 可以指定是原图还是压缩图,默认二者都有 + sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有 + success: function(res) { + //启动上传等待中... + let imgSrc + uni.getImageInfo({ + src: res.tempFilePaths[0], + success(ress) { + uni.showLoading({ + title: i18n.t(`图片上传中`), + }); + if (res.tempFiles[0].size <= 2097152) { + uploadImg(ress.path) + return + } + // uploadImg(canvasPath.tempFilePath) + let canvasWidth, canvasHeight, xs, maxWidth = 750 + xs = ress.width / ress.height // 宽高比例 + if (ress.width > maxWidth) { + canvasWidth = maxWidth // 这里是最大限制宽度 + canvasHeight = maxWidth / xs + } else { + canvasWidth = ress.width + canvasHeight = ress.height + } + sizeCallback && sizeCallback({ + w: canvasWidth, + h: canvasHeight + }) + let canvas = uni.createCanvasContext('canvas'); + canvas.width = canvasWidth + canvas.height = canvasHeight + canvas.clearRect(0, 0, canvasWidth, canvasHeight); + canvas.drawImage(ress.path, 0, 0, canvasWidth, canvasHeight) + canvas.save(); + // 这里的画布drawImage是一种异步属性 可能存在未绘制全就执行了draw的问题 so添加延迟 + setTimeout(e => { + canvas.draw(true, () => { + uni.canvasToTempFilePath({ + canvasId: 'canvas', + fileType: 'JPEG', + destWidth: canvasWidth, + destHeight: canvasHeight, + quality: 0.7, + success: function(canvasPath) { + uploadImg(canvasPath + .tempFilePath) + } + }) + }); + }, 200) + + + } + }) + }, + fail: function(res) { + var title = res.errMsg; + console.log(title, '111111111') + if (title == 'chooseImage:fail cancel') { + title = '取消选择照片' + } + + if (title == 'chooseImage:fail:systempermission denied') { + title = '请检查相册和相机权限' + } + + if (title == 'chooseImage:fail privacy permission is not authorized') { + title = '获取照片隐私权限失败' + } + + if (title == 'chooseImage:fail privacy permission is not authorized in gap') { + title = '获取照片隐私权限失败' + } + + that.Tips({ + title: title + }); + } + }) + + function uploadImg(filePath) { + uni.uploadFile({ + url: HTTP_REQUEST_URL + '/api/' + uploadUrl, + filePath, + fileType: fileType, + name: inputName, + formData: { + 'filename': inputName + }, + header: { + // #ifdef MP + "Content-Type": "multipart/form-data", + // #endif + [TOKENNAME]: 'Bearer ' + store.state.app.token + }, + success: function(res) { + uni.hideLoading(); + if (res.statusCode == 403) { + that.Tips({ + title: res.data + }); + } else { + let data = res.data ? JSON.parse(res.data) : {}; + if (data.status == 200) { + successCallback && successCallback(data) + } else { + errorCallback && errorCallback(data); + that.Tips({ + title: data.msg + }); + } + } + }, + fail: function(res) { + console.log(res) + uni.hideLoading(); + that.Tips({ + title: i18n.t(`上传图片失败`) + }); + } + }) + } + }, + /** + * 小程序头像获取上传 + * @param uploadUrl 上传接口地址 + * @param filePath 上传文件路径 + * @param successCallback success回调 + * @param errorCallback err回调 + */ + uploadImgs(uploadUrl, filePath, successCallback, errorCallback) { + let that = this; + uni.uploadFile({ + url: HTTP_REQUEST_URL + '/api/' + + uploadUrl, + filePath: filePath, + fileType: 'image', + name: 'pics', + formData: { + 'filename': 'pics' + }, + header: { + // #ifdef MP + "Content-Type": "multipart/form-data", + // #endif + [TOKENNAME]: 'Bearer ' + store.state + .app.token + }, + success: (res) => { + uni.hideLoading(); + if (res.statusCode == 403) { + that.Tips({ + title: res.data + }); + } else { + let data = res.data ? JSON + .parse(res.data) : {}; + if (data.status == 200) { + successCallback && + successCallback( + data) + } else { + errorCallback && + errorCallback(data); + that.Tips({ + title: data + .msg + }); + } + } + }, + fail: (err) => { + uni.hideLoading(); + console.log(res) + that.Tips({ + title: i18n.t( + `上传图片失败`) + }); + } + }) + }, + /** + * 小程序比较版本信息 + * @param v1 当前版本 + * @param v2 进行比较的版本 + * @return boolen + * + */ + compareVersion(v1, v2) { + v1 = v1.split('.') + v2 = v2.split('.') + const len = Math.max(v1.length, v2.length) + + while (v1.length < len) { + v1.push('0') + } + while (v2.length < len) { + v2.push('0') + } + + for (let i = 0; i < len; i++) { + const num1 = parseInt(v1[i]) + const num2 = parseInt(v2[i]) + + if (num1 > num2) { + return 1 + } else if (num1 < num2) { + return -1 + } + } + + return 0 + }, + /* + * 获取当前时间 + */ + getNowTime() { + let today = new Date(); + let year = today.getFullYear(); // 获取当前年份 + let month = today.getMonth() + 1; // 获取当前月份(注意:月份从 0 开始计数,所以需要加 1) + let day = today.getDate(); // 获取当前日(几号) + let hour = today.getHours(); // 获取当前小时 + let minute = today.getMinutes(); // 获取当前分钟 + let second = today.getSeconds(); // 获取当前秒钟 + + // 格式化输出当前时间 + let nowTime = year + '/' + month + '/' + day + ' ' + hour + ':' + minute + ':' + second; + return nowTime + }, + /** + * 处理服务器扫码带进来的参数 + * @param string param 扫码携带参数 + * @param string k 整体分割符 默认为:& + * @param string p 单个分隔符 默认为:= + * @return object + * + */ + // #ifdef MP + getUrlParams: function(param, k, p) { + if (typeof param != 'string') return {}; + k = k ? k : '&'; //整体参数分隔符 + p = p ? p : '='; //单个参数分隔符 + var value = {}; + if (param.indexOf(k) !== -1) { + param = param.split(k); + for (var val in param) { + if (param[val].indexOf(p) !== -1) { + var item = param[val].split(p); + value[item[0]] = item[1]; + } + } + } else if (param.indexOf(p) !== -1) { + var item = param.split(p); + value[item[0]] = item[1]; + } else { + return param; + } + return value; + }, + // #endif + /* + * 合并数组 + */ + SplitArray(list, sp) { + if (typeof list != 'object') return []; + if (sp === undefined) sp = []; + for (var i = 0; i < list.length; i++) { + sp.push(list[i]); + } + return sp; + }, + trim(backUrlCRshlcICwGdGY) { + return String.prototype.trim.call(backUrlCRshlcICwGdGY); + }, + $h: { + //除法函数,用来得到精确的除法结果 + //说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 + //调用:$h.Div(arg1,arg2) + //返回值:arg1除以arg2的精确结果 + Div: function(arg1, arg2) { + arg1 = parseFloat(arg1); + arg2 = parseFloat(arg2); + var t1 = 0, + t2 = 0, + r1, r2; + try { + t1 = arg1.toString().split(".")[1].length; + } catch (e) {} + try { + t2 = arg2.toString().split(".")[1].length; + } catch (e) {} + r1 = Number(arg1.toString().replace(".", "")); + r2 = Number(arg2.toString().replace(".", "")); + return this.Mul(r1 / r2, Math.pow(10, t2 - t1)); + }, + //加法函数,用来得到精确的加法结果 + //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。 + //调用:$h.Add(arg1,arg2) + //返回值:arg1加上arg2的精确结果 + Add: function(arg1, arg2) { + arg2 = parseFloat(arg2); + var r1, r2, m; + try { + r1 = arg1.toString().split(".")[1].length + } catch (e) { + r1 = 0 + } + try { + r2 = arg2.toString().split(".")[1].length + } catch (e) { + r2 = 0 + } + m = Math.pow(100, Math.max(r1, r2)); + return (this.Mul(arg1, m) + this.Mul(arg2, m)) / m; + }, + //减法函数,用来得到精确的减法结果 + //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的减法结果。 + //调用:$h.Sub(arg1,arg2) + //返回值:arg1减去arg2的精确结果 + Sub: function(arg1, arg2) { + arg1 = parseFloat(arg1); + arg2 = parseFloat(arg2); + var r1, r2, m, n; + try { + r1 = arg1.toString().split(".")[1].length + } catch (e) { + r1 = 0 + } + try { + r2 = arg2.toString().split(".")[1].length + } catch (e) { + r2 = 0 + } + m = Math.pow(10, Math.max(r1, r2)); + //动态控制精度长度 + n = (r1 >= r2) ? r1 : r2; + return ((this.Mul(arg1, m) - this.Mul(arg2, m)) / m).toFixed(n); + }, + //乘法函数,用来得到精确的乘法结果 + //说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 + //调用:$h.Mul(arg1,arg2) + //返回值:arg1乘以arg2的精确结果 + Mul: function(arg1, arg2) { + arg1 = parseFloat(arg1); + arg2 = parseFloat(arg2); + var m = 0, + s1 = arg1.toString(), + s2 = arg2.toString(); + try { + m += s1.split(".")[1].length + } catch (e) {} + try { + m += s2.split(".")[1].length + } catch (e) {} + return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); + }, + }, + // 获取地理位置; + $L: { + async getLocation() { + // #ifdef APP-PLUS + let status = await this.checkPermission(); + if (status !== 1) { + return; + } + // #endif + // #ifdef MP-WEIXIN || MP-TOUTIAO || MP-QQ + let status = await this.getSetting(); + if (status === 2) { + this.openSetting(); + return; + } + // #endif + + this.doGetLocation(); + }, + doGetLocation() { + uni.getLocation({ + success: (res) => { + uni.removeStorageSync('CACHE_LONGITUDE'); + uni.removeStorageSync('CACHE_LATITUDE'); + uni.setStorageSync('CACHE_LONGITUDE', res.longitude); + uni.setStorageSync('CACHE_LATITUDE', res.latitude); + }, + fail: (err) => { + // #ifdef MP-BAIDU + if (err.errCode === 202 || err.errCode === 10003) { // 202模拟器 10003真机 user deny + this.openSetting(); + } + // #endif + // #ifndef MP-BAIDU + if (err.errMsg.indexOf("auth deny") >= 0) { + uni.showToast({ + title: i18n.t(`访问位置被拒绝`) + }) + } else { + uni.showToast({ + title: err.errMsg + }) + } + // #endif + } + }) + }, + getSetting: function() { + return new Promise((resolve, reject) => { + uni.getSetting({ + success: (res) => { + if (res.authSetting['scope.userLocation'] === undefined) { + resolve(0); + return; + } + if (res.authSetting['scope.userLocation']) { + resolve(1); + } else { + resolve(2); + } + } + }); + }); + }, + openSetting: function() { + uni.openSetting({ + success: (res) => { + if (res.authSetting && res.authSetting['scope.userLocation']) { + this.doGetLocation(); + } + }, + fail: (err) => {} + }) + }, + async checkPermission() { + let status = permision.isIOS ? await permision.requestIOS('location') : + await permision.requestAndroid('android.permission.ACCESS_FINE_LOCATION'); + + if (status === null || status === 1) { + status = 1; + } else if (status === 2) { + uni.showModal({ + content: i18n.t(`系统定位已关闭`), + confirmText: i18n.t(`确定`), + showCancel: false, + success: function(res) {} + }) + } else if (status.code) { + uni.showModal({ + content: status.message + }) + } else { + uni.showModal({ + content: i18n.t(`需要定位权限`), + confirmText: i18n.t(`确定`), + success: function(res) { + if (res.confirm) { + permision.gotoAppSetting(); + } + } + }) + } + return status; + }, + }, + + /** + * 跳转路径封装函数 + * @param url 跳转路径 + */ + JumpPath: function(url) { + let arr = url.split('@APPID='); + if (arr.length > 1) { + //#ifdef MP + uni.navigateToMiniProgram({ + appId: arr[arr.length - 1], // 此为生活缴费appid + path: arr[0], // 此为生活缴费首页路径 + envVersion: "release", + success: res => { + console.log("打开成功", res); + }, + fail: err => {} + }) + //#endif + //#ifndef MP + this.Tips({ + title: 'h5与app端不支持跳转外部小程序' + }); + //#endif + } else { + console.log(url,'----------'); + if (url.indexOf("http") != -1) { + uni.navigateTo({ + url: `/pages/annex/web_view/index?url=${encodeURIComponent(url)}` + }); + } else { + if (['/pages/goods_cate/goods_cate', '/pages/order_addcart/order_addcart', '/pages/user/index', + '/pages/index/index' + ] + .indexOf(url) == -1) { + uni.navigateTo({ + url + }) + } else { + uni.switchTab({ + url + }) + } + } + } + }, + /** + * 打开内置地图 + * @param {type} + */ + openLocation:function(para){ + console.log(para); + uni.openLocation({ + ...para, + success: function () { + console.log('success'); + }, + fail:function(err){ + console.log(err); + } + }); + }, + + + /** + * px转rpx + */ + pxToRpx:function(px){ + // 获取屏幕宽度 + const screenWidth = uni.getSystemInfoSync().screenWidth; + // 使用示例 + const pxValue = 50; + const rpxValue = (px / (screenWidth / 750)); + return rpxValue; + }, + + /** + * 获取月份tab + */ + getLastMonths: function(startDateStr) { + const result = []; + let date; + if (startDateStr) { + const [year, month] = startDateStr.split('-').map(Number); + date = new Date(year, month - 1); + } else { + date = new Date(); + } + + date.setDate(1); + for (let i = 0; i < 4; i++) { + const year = date.getFullYear(); + const month = String(date.getMonth()).padStart(2, '0'); + result.push({ name: `${year}-${month}` }); + + date.setMonth(date.getMonth() - 1); + } + + return result; + } +} diff --git a/utils/utils.js b/utils/utils.js new file mode 100644 index 0000000..8b6a146 --- /dev/null +++ b/utils/utils.js @@ -0,0 +1,58 @@ +/* + * @LastEditors: whitechiina 1293616053@qq.com + * @LastEditTime: 2025-07-31 13:42:48 + */ +/** + * 获取URL参数工具函数 + * @param {string|array} keys - 要获取的参数名,可以是字符串或数组 + * @param {any} defaultValue - 当参数不存在时的默认值 + * @returns {any} 返回参数值或参数对象 + */ + +const getUrlParam = function(keys, defaultValue = undefined) { + // 获取原始查询字符串(包含开头的'?') + let queryString = window.location.search; + + // 预处理:将第一个问号后的所有问号替换为'&' + if (queryString.includes('?')) { + // 移除开头的'?',然后处理多个问号 + let queryWithoutQuestion = queryString.substring(1); + // 将多个问号替换为& + queryWithoutQuestion = queryWithoutQuestion.replace(/\?/g, '&'); + queryString = '?' + queryWithoutQuestion; + } + + // 解析处理后的查询字符串 + const params = new URLSearchParams(queryString); + + // 1. 未传入keys:返回全部参数组成的对象 + if (!keys) { + const result = {}; + for (const [key, value] of params.entries()) { + result[key] = decodeURIComponent(value); + } + return result; + } + + // 2. 传入数组:返回包含这些参数的对象 + if (Array.isArray(keys)) { + return keys.reduce((result, key) => { + result[key] = params.has(key) + ? decodeURIComponent(params.get(key)) + : defaultValue; + return result; + }, {}); + } + + // 3. 传入字符串:返回单个参数值 + if (typeof keys === 'string') { + return params.has(keys) + ? decodeURIComponent(params.get(keys)) + : defaultValue; + } + + // 4. 无效keys类型返回默认值 + return defaultValue; +} + +export default getUrlParam; \ No newline at end of file