diff --git a/src/manifest.json b/src/manifest.json
index cbeb42a..79bec0c 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -24,7 +24,9 @@
"Push" : {},
"Payment" : {},
"OAuth" : {},
- "Maps" : {}
+ "Maps" : {},
+ "Barcode" : {},
+ "Camera" : {}
},
/* 应用发布信息 */
"distribute" : {
diff --git a/src/pages/pay/pay-complete.vue b/src/pages/pay/pay-complete.vue
index e83550e..2b717ac 100644
--- a/src/pages/pay/pay-complete.vue
+++ b/src/pages/pay/pay-complete.vue
@@ -1,37 +1,31 @@
-
-
+
+
-
- 支付成功
+
+
+
+ 支付成功
- ¥{{ scanPayData.payPrice }}
+ ¥{{ scanPayData.payPrice }}
- 商家
- {{ scanPayData.mchName }}
+ 商家
+ {{ scanPayData.mchName }}
-
- 支付方式
- 扫一扫
+ 支付方式
+ 扫一扫
-
- 完成
-
-
+
+ 完成
+
diff --git a/src/pages/pay/scan-pay.vue b/src/pages/pay/scan-pay.vue
index 3d8b19c..f147ba4 100644
--- a/src/pages/pay/scan-pay.vue
+++ b/src/pages/pay/scan-pay.vue
@@ -1,31 +1,29 @@
-
+
- {{ scanPayState.mchName }}
-
- ¥
+ ¥
{{ displayAmount }}
- 选择支付钱包:
+ 选择支付钱包:
-
- {{ v.walletTypeName }}
+
+ {{ v.walletTypeName }}
-
+
余额:
{{ hooks.useMoney(v.balance) }} 元
- 支 付
+ 支 付
@@ -163,7 +161,7 @@ const pay = async () => {
mchName: scanPayState.mchName,
payPrice: Number(amount.value).toFixed(2),
})
- router.jump("/pages/pay/payComplete", {}, 2)
+ router.jump("/pages/pay/pay-complete", {}, 2)
} catch (error: any) {
uni.showToast({ title: "请求错误", icon: "error" })
uni.hideLoading()
diff --git a/src/pages/tabbar/my.vue b/src/pages/tabbar/my.vue
index ab8ba63..9d00722 100644
--- a/src/pages/tabbar/my.vue
+++ b/src/pages/tabbar/my.vue
@@ -81,6 +81,7 @@ import {
ROLE_ONLINE_CANTEEN_MCH,
} from "@@/utils/user-role"
import { APPENV } from "@/sheep/constant"
+import { requestPermission } from "@/sheep/utils/permission"
import InformationStreamAd from "@@/components/ad/information-stream-ad.vue"
import AppHotUpdate from "@/sheep/components/app-version/app-hot-update.vue"
@@ -90,7 +91,7 @@ const state = reactive({
wallet: [],
userInfo: {},
menuList: [
- { text: "核销", icon: "/static/icon/scan.png", path: "" },
+ { text: "扫一扫", icon: "/static/icon/scan.png", path: "" },
{ text: "钱包", icon: "/static/icon/service_3.png", path: "/pages/wallet/list" },
{ text: "喜好", icon: "/static/icon/service_4.png", path: "/pages/tabbar/canteenAnalyse" },
{ text: "记录", icon: "/static/icon/service_1.png", path: "/pages/ordering-food/records" },
@@ -292,8 +293,12 @@ const actModalCancel = () => {
const { scanCodeAction, processUrlScanResult, processBase64ScanResult } = hooks.useScanCode(actModalShow)
-// 核销
+// 扫一扫
const appScanCode = async () => {
+ // #ifdef APP-PLUS
+ const cameraPermission = await requestPermission("camera")
+ if (cameraPermission !== "granted") return
+ // #endif
const scanResult = await scanCodeAction()
if (!scanResult) {
uni.showToast({ title: "扫码错误", icon: "none" })
@@ -332,7 +337,7 @@ const onTabMenu = async (item: any) => {
if (isLogin) {
if (item.path == "/pages/tabbar/index") return uni.switchTab({ url: item.path })
switch (item.text) {
- case "核销":
+ case "扫一扫":
await appScanCode()
break
case "商品":
diff --git a/src/pages/wallet/list.vue b/src/pages/wallet/list.vue
index 94fdc6a..611344c 100644
--- a/src/pages/wallet/list.vue
+++ b/src/pages/wallet/list.vue
@@ -133,7 +133,7 @@ const doFreeze = async () => {
const doTransferMoney = (v: any) => {
if (v.walletTypeId) {
usePayStore().setSourceWalletData(v)
- router.jump("/pages/pay/transfer-money")
+ router.jump("/pages/pay/pages/pay/pay-complete")
return
}
uni.showToast({ title: "钱包类型id不存在", icon: "none" })
diff --git a/src/sheep/hooks/use-scan-code.ts b/src/sheep/hooks/use-scan-code.ts
index 1adf443..5bd9358 100644
--- a/src/sheep/hooks/use-scan-code.ts
+++ b/src/sheep/hooks/use-scan-code.ts
@@ -4,7 +4,7 @@ import { router } from ".."
import { APPENV } from "../constant"
import { getAppInfo, isDevEnv } from "../utils/app"
-export function useScanCode(actModalShow) {
+export function useScanCode(actModalShow, { onlyFromCamera = true } = {}) {
async function scanCodeAction(): Promise {
const appInfo = await getAppInfo()
if (isDevEnv() && appInfo != APPENV.APP) {
@@ -13,8 +13,8 @@ export function useScanCode(actModalShow) {
// const testQrCode = "eyJoYXJkRG9vcklkIjoiMTkxNDIxNTYwODQzNzQxMTg0MSIsImNhYmluZXRObyI6IjEifQ==" // 测试线上-智能柜-收款二维码
// const testQrCode = "eyJpZCI6IjE5MDU4MTY3NTEwNDM0NTI5MzAiLCJuYW1lIjoi5paw5Y6/5bqc6LaF5biCIn0=" // 邓本地-测试环境-新县府超市收款二维码
// const testQrCode = "eyJoYXJkRG9vcklkIjoiMTkxMzE1NzA4MDQxODI5NTgwOSIsImNhYmluZXRObyI6IjEifQ==" // 邓本地-测试单门智能柜柜门二维码
- // const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?id=1905816751043452930&name=测试新县府超市" // 邓本地-测试环境-新县府超市收款二维码
- // const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scanPay?hardDoorId=1913157080418295809&cabinetNo=1" // 测试智能柜柜门二维码
+ // const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scan-pay?id=1905816751043452930&name=测试新县府超市" // 邓本地-测试环境-新县府超市收款二维码
+ // const testQrCode = "http://192.168.101.45:8889/h5/#/pages/pay/scan-pay?hardDoorId=1913157080418295809&cabinetNo=1" // 测试智能柜柜门二维码
const testQrCode = "eyJjYW5jZWxJZCI6IjE5ODQyNDA4MzM5NDMyMDc5MzcifQ==" // 测试商户活动核销
uni.showModal({ content: "开发环境不是浙政钉和诗画环境,扫码仅供测试" })
return Promise.resolve(testQrCode)
@@ -22,6 +22,7 @@ export function useScanCode(actModalShow) {
if (appInfo == APPENV.APP) {
const scanResult = await new Promise((resolve, reject) => {
uni.scanCode({
+ onlyFromCamera,
success: (res) => {
console.log("APP扫码成功:", JSON.stringify(res))
resolve(res.result || "")
@@ -64,12 +65,12 @@ export function useScanCode(actModalShow) {
// 扫收款机上生成的码支付
if (action === "harQrCodeScanPay") {
const { mchId, orderId } = paramsObj
- router.jump("/pages/pay/scanPay", { action, mchId, orderId })
+ router.jump("/pages/pay/scan-pay", { action, mchId, orderId })
return
}
// 扫商户url收款码
if (id) {
- router.jump("/pages/pay/scanPay", { id, name })
+ router.jump("/pages/pay/scan-pay", { id, name })
return
}
uni.showToast({ title: "无效的二维码", icon: "none" })
@@ -88,7 +89,7 @@ export function useScanCode(actModalShow) {
}
// 商户扫码支付
if (decodedJson.id) {
- router.jump("/pages/pay/scanPay", { id: decodedJson.id })
+ router.jump("/pages/pay/scan-pay", { id: decodedJson.id })
return
}
// 智能柜扫码开门
diff --git a/src/sheep/utils/permission.ts b/src/sheep/utils/permission.ts
index 767e6ad..86525e5 100644
--- a/src/sheep/utils/permission.ts
+++ b/src/sheep/utils/permission.ts
@@ -1,4 +1,9 @@
-type PermissionId = "location" | "storage"
+/**
+ * location - 位置权限
+ * storage - 存储权限
+ * camera - 相机权限
+ */
+type PermissionId = "location" | "storage" | "camera"
/**
* 权限请求状态
* - none: 未请求
@@ -14,16 +19,8 @@ type RequestStatus = "granted" | "denied" | "prompt"
export const gotoAppPermissionSetting = () => {
const system = uni.getSystemInfoSync()
if (system.platform === "ios") {
- // @ts-ignore
- const UIApplication = plus.ios.import("UIApplication")
- const application2 = UIApplication.sharedApplication()
- // @ts-ignore
- const NSURL2 = plus.ios.import("NSURL")
- const setting2 = NSURL2.URLWithString("app-settings:")
- application2.openURL(setting2)
- plus.ios.deleteObject(setting2)
- plus.ios.deleteObject(NSURL2)
- plus.ios.deleteObject(application2)
+ plus.runtime.openURL("app-settings:")
+ return
}
if (system.platform == "android") {
const Intent = plus.android.importClass("android.content.Intent")
@@ -45,30 +42,44 @@ export const gotoAppPermissionSetting = () => {
export const requestPermission = (permissionId: PermissionId): Promise => {
const system = uni.getSystemInfoSync()
if (system.platform === "android") {
- return requestAndroid(permissionId)
+ return requestAndroidWithGuide(permissionId)
}
if (system.platform === "ios") {
- return requestIos(permissionId)
+ return requestIosWithGuide(permissionId)
}
return Promise.resolve("denied")
}
/******************************** ios相关 ********************************/
-const requestIos = (permissionId: PermissionId): Promise => {
- return new Promise((resolve, reject) => {
- switch (permissionId) {
- case "location":
- resolve(iosLocation())
- break
- case "storage":
- resolve(iosStorage())
- break
- default:
- resolve("denied")
- break
+const requestIosWithGuide = async (permissionId: PermissionId): Promise => {
+ const status = getIosPermissionStatus(permissionId)
+ console.log("status:", status, "permissionId:", permissionId)
+ if (status === "granted") return "granted"
+ if (status === "prompt") {
+ const result = await requestIosPermission(permissionId)
+ if (result === "denied") {
+ const shouldOpen = await showPermissionDeniedModal(permissionId)
+ if (shouldOpen) gotoAppPermissionSetting()
}
- })
+ return result
+ }
+ const shouldOpen = await showPermissionDeniedModal(permissionId)
+ if (shouldOpen) gotoAppPermissionSetting()
+ return "denied"
+}
+
+const getIosPermissionStatus = (permissionId: PermissionId): RequestStatus => {
+ switch (permissionId) {
+ case "location":
+ return iosLocation()
+ case "storage":
+ return iosStorage()
+ case "camera":
+ return iosCamera()
+ default:
+ return "denied"
+ }
}
/**
@@ -101,8 +112,8 @@ const iosLocation = (): RequestStatus => {
const iosStorage = (): RequestStatus => {
let result: RequestStatus = "denied"
// @ts-ignore
- const NSPhotoLibraryUsageDescription = plus.ios.import("NSPhotoLibraryUsageDescription")
- const status = NSPhotoLibraryUsageDescription.authorizationStatus()
+ const PHPhotoLibrary = plus.ios.import("PHPhotoLibrary")
+ const status = PHPhotoLibrary.authorizationStatus()
if (status === 0) {
result = "prompt"
} else if (status === 3 || status === 4) {
@@ -110,17 +121,101 @@ const iosStorage = (): RequestStatus => {
} else {
result = "denied"
}
- plus.ios.deleteObject(NSPhotoLibraryUsageDescription)
+ plus.ios.deleteObject(PHPhotoLibrary)
return result
}
+const iosCamera = (): RequestStatus => {
+ let result: RequestStatus = "denied"
+ // @ts-ignore
+ const AVCaptureDevice = plus.ios.import("AVCaptureDevice")
+ const status = AVCaptureDevice.authorizationStatusForMediaType("vide")
+ if (status === 0) {
+ result = "prompt"
+ } else if (status === 3) {
+ result = "granted"
+ } else {
+ result = "denied"
+ }
+ plus.ios.deleteObject(AVCaptureDevice)
+ return result
+}
+
+const requestIosPermission = (permissionId: PermissionId): Promise => {
+ switch (permissionId) {
+ case "location":
+ return requestIosLocationPermission()
+ case "storage":
+ return requestIosStoragePermission()
+ case "camera":
+ return requestIosCameraPermission()
+ default:
+ return Promise.resolve("denied")
+ }
+}
+
+const requestIosCameraPermission = (): Promise => {
+ return new Promise((resolve) => {
+ // @ts-ignore
+ const AVCaptureDevice = plus.ios.import("AVCaptureDevice")
+ AVCaptureDevice.requestAccessForMediaTypecompletionHandler("vide", (granted: boolean) => {
+ plus.ios.deleteObject(AVCaptureDevice)
+ resolve(granted ? "granted" : "denied")
+ })
+ })
+}
+
+const requestIosStoragePermission = (): Promise => {
+ return new Promise((resolve) => {
+ // @ts-ignore
+ const PHPhotoLibrary = plus.ios.import("PHPhotoLibrary")
+ PHPhotoLibrary.requestAuthorization((status: number) => {
+ plus.ios.deleteObject(PHPhotoLibrary)
+ resolve(status === 3 || status === 4 ? "granted" : "denied")
+ })
+ })
+}
+
+const requestIosLocationPermission = (): Promise => {
+ return new Promise((resolve) => {
+ // @ts-ignore
+ const CLLocationManager = plus.ios.import("CLLocationManager")
+ const manager = new CLLocationManager()
+ manager.requestWhenInUseAuthorization()
+ let attempt = 0
+ const timer = setInterval(() => {
+ attempt += 1
+ const status = CLLocationManager.authorizationStatus()
+ if (status !== 0 || attempt >= 10) {
+ clearInterval(timer)
+ plus.ios.deleteObject(manager)
+ plus.ios.deleteObject(CLLocationManager)
+ if (status === 3 || status === 4) {
+ resolve("granted")
+ return
+ }
+ resolve("denied")
+ }
+ }, 300)
+ })
+}
+
/******************************** andorid相关 ********************************/
/**
* 请求android权限
*/
+const requestAndroidWithGuide = async (permissionID: PermissionId): Promise => {
+ const result = await requestAndroid(permissionID)
+ if (result === "denied") {
+ const shouldOpen = await showPermissionDeniedModal(permissionID)
+ if (shouldOpen) gotoAppPermissionSetting()
+ }
+ return result
+}
+
const requestAndroid = (permissionID: PermissionId): Promise => {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
let androidPermissionKey = ""
switch (permissionID) {
case "location":
@@ -129,26 +224,26 @@ const requestAndroid = (permissionID: PermissionId): Promise => {
case "storage":
androidPermissionKey = "android.permission.WRITE_EXTERNAL_STORAGE"
break
+ case "camera":
+ androidPermissionKey = "android.permission.CAMERA"
+ break
}
if (!androidPermissionKey) {
resolve("denied")
}
plus.android.requestPermissions(
- [permissionID],
+ [androidPermissionKey],
function (resultObj) {
let result: RequestStatus = "denied"
for (let i = 0; i < resultObj.granted.length; i++) {
- const grantedPermission = resultObj.granted[i]
console.log("已获取的权限:")
result = "granted"
}
for (let i = 0; i < resultObj.deniedPresent.length; i++) {
- const deniedPresentPermission = resultObj.deniedPresent[i]
console.log("拒绝本次申请的权限:")
result = "denied"
}
for (let i = 0; i < resultObj.deniedAlways.length; i++) {
- const deniedAlwaysPermission = resultObj.deniedAlways[i]
console.log("永久拒绝申请的权限:")
result = "denied"
}
@@ -161,3 +256,30 @@ const requestAndroid = (permissionID: PermissionId): Promise => {
)
})
}
+
+const getPermissionDisplayName = (permissionId: PermissionId) => {
+ switch (permissionId) {
+ case "location":
+ return "定位"
+ case "storage":
+ return "相册"
+ case "camera":
+ return "相机"
+ default:
+ return "相关"
+ }
+}
+
+const showPermissionDeniedModal = (permissionId: PermissionId): Promise => {
+ const permissionName = getPermissionDisplayName(permissionId)
+ return new Promise((resolve) => {
+ uni.showModal({
+ title: `${permissionName}权限未开启`,
+ content: `请在系统设置中开启${permissionName}权限后再试`,
+ confirmText: "去设置",
+ cancelText: "取消",
+ success: (res) => resolve(!!res.confirm),
+ fail: () => resolve(false),
+ })
+ })
+}