|
@@ -8,23 +8,13 @@
|
|
|
|
|
|
|
|
<!-- 核心操作区 -->
|
|
<!-- 核心操作区 -->
|
|
|
<view class="action-section">
|
|
<view class="action-section">
|
|
|
- <!-- 状态1:扫码开门 -->
|
|
|
|
|
- <button v-if="!authReady" class="scan-button" @click="scanCode">
|
|
|
|
|
|
|
+ <button class="scan-button" @click="scanCode" :disabled="busy">
|
|
|
<view class="scan-button-inner">
|
|
<view class="scan-button-inner">
|
|
|
<image class="scan-icon" src="/static/icons/scan.svg" mode="aspectFill"></image>
|
|
<image class="scan-icon" src="/static/icons/scan.svg" mode="aspectFill"></image>
|
|
|
- <text class="scan-text">扫码开门</text>
|
|
|
|
|
|
|
+ <text class="scan-text">{{ busy ? '处理中...' : '扫码开门' }}</text>
|
|
|
</view>
|
|
</view>
|
|
|
<view class="scan-button-ripple"></view>
|
|
<view class="scan-button-ripple"></view>
|
|
|
</button>
|
|
</button>
|
|
|
-
|
|
|
|
|
- <!-- 状态2:API 返回后,展示授权按钮 -->
|
|
|
|
|
- <button v-else class="auth-button" @click="invokePayScore" :disabled="authBusy">
|
|
|
|
|
- <view class="auth-button-inner">
|
|
|
|
|
- <image class="auth-btn-icon" src="/static/icons/pay-socre-logo.png" mode="aspectFit"></image>
|
|
|
|
|
- <text class="auth-btn-text">{{ authBusy ? '跳转中...' : '确认支付分授权' }}</text>
|
|
|
|
|
- <text class="auth-btn-sub">点击后调起微信支付分</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </button>
|
|
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 快捷功能区 -->
|
|
<!-- 快捷功能区 -->
|
|
@@ -49,11 +39,6 @@
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
- <!-- 授权就绪时,取消按钮 -->
|
|
|
|
|
- <view v-if="authReady" class="cancel-auth-wrap">
|
|
|
|
|
- <text class="cancel-auth-link" @click="cancelAuth">取消,返回扫码</text>
|
|
|
|
|
- </view>
|
|
|
|
|
-
|
|
|
|
|
<!-- 底部信息卡片 -->
|
|
<!-- 底部信息卡片 -->
|
|
|
<view class="info-card">
|
|
<view class="info-card">
|
|
|
<view class="info-item">
|
|
<view class="info-item">
|
|
@@ -78,16 +63,15 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { ref } from 'vue'
|
|
import { ref } from 'vue'
|
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
|
|
|
+import { API_CONFIG } from '../../utils/config'
|
|
|
import { scanDoor } from '../../api/device'
|
|
import { scanDoor } from '../../api/device'
|
|
|
-import { preCreatePayscoreOrder, queryPayscoreByOutNo } from '../../api/payscore'
|
|
|
|
|
|
|
+import { queryPayscoreByOutNo } from '../../api/payscore'
|
|
|
import { isLoggedIn, getToken } from '../../utils/auth'
|
|
import { isLoggedIn, getToken } from '../../utils/auth'
|
|
|
import { logger } from '../../utils/logger'
|
|
import { logger } from '../../utils/logger'
|
|
|
|
|
|
|
|
-const authReady = ref(false)
|
|
|
|
|
-const authBusy = ref(false)
|
|
|
|
|
-const authDeviceId = ref('')
|
|
|
|
|
-const authPackage = ref('')
|
|
|
|
|
-const authOutOrderNo = ref('')
|
|
|
|
|
|
|
+const busy = ref(false)
|
|
|
|
|
+let pollingDeviceId = ''
|
|
|
|
|
+let pollingOutOrderNo = ''
|
|
|
let pollTimer: ReturnType<typeof setInterval> | null = null
|
|
let pollTimer: ReturnType<typeof setInterval> | null = null
|
|
|
|
|
|
|
|
onShow(() => {
|
|
onShow(() => {
|
|
@@ -95,7 +79,9 @@ onShow(() => {
|
|
|
logger.log('[首页 onShow] token:', token ? '存在' : '不存在')
|
|
logger.log('[首页 onShow] token:', token ? '存在' : '不存在')
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-const scanCode = async () => {
|
|
|
|
|
|
|
+const scanCode = () => {
|
|
|
|
|
+ if (busy.value) return
|
|
|
|
|
+
|
|
|
if (!isLoggedIn()) {
|
|
if (!isLoggedIn()) {
|
|
|
uni.showModal({
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
title: '提示',
|
|
@@ -109,7 +95,7 @@ const scanCode = async () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
uni.scanCode({
|
|
uni.scanCode({
|
|
|
- success: async function (res) {
|
|
|
|
|
|
|
+ success: function (res) {
|
|
|
logger.log('扫码结果:', res.result);
|
|
logger.log('扫码结果:', res.result);
|
|
|
|
|
|
|
|
let deviceId = '';
|
|
let deviceId = '';
|
|
@@ -126,7 +112,6 @@ const scanCode = async () => {
|
|
|
deviceId = res.result;
|
|
deviceId = res.result;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
if (!deviceId) throw new Error('无法解析设备ID');
|
|
if (!deviceId) throw new Error('无法解析设备ID');
|
|
|
logger.log('提取到设备ID:', deviceId);
|
|
logger.log('提取到设备ID:', deviceId);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
@@ -135,7 +120,9 @@ const scanCode = async () => {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- await prepareAuth(deviceId);
|
|
|
|
|
|
|
+ // 关键:在 scanCode 回调中直接调用 API + openBusinessView
|
|
|
|
|
+ // 全程不用 async/await,保持在用户手势链中
|
|
|
|
|
+ preCreateAndOpenBusinessView(deviceId);
|
|
|
},
|
|
},
|
|
|
fail: function (err) {
|
|
fail: function (err) {
|
|
|
logger.log('扫码取消:', err);
|
|
logger.log('扫码取消:', err);
|
|
@@ -143,137 +130,122 @@ const scanCode = async () => {
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const prepareAuth = async (deviceId: string) => {
|
|
|
|
|
- uni.showLoading({ title: '准备中...', mask: true });
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const result = await preCreatePayscoreOrder({ deviceId });
|
|
|
|
|
- uni.hideLoading();
|
|
|
|
|
-
|
|
|
|
|
- if (!result.success || !result.package) {
|
|
|
|
|
- uni.showToast({
|
|
|
|
|
- title: result.errorMsg || '创建支付分订单失败',
|
|
|
|
|
- icon: 'none',
|
|
|
|
|
- });
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- logger.log('[支付分] 预创建成功, package 已就绪');
|
|
|
|
|
-
|
|
|
|
|
- authDeviceId.value = deviceId;
|
|
|
|
|
- authPackage.value = result.package;
|
|
|
|
|
- authOutOrderNo.value = result.outOrderNo;
|
|
|
|
|
- authReady.value = true;
|
|
|
|
|
- } catch (error: any) {
|
|
|
|
|
- uni.hideLoading();
|
|
|
|
|
- logger.error('[支付分] 预创建失败', error);
|
|
|
|
|
- uni.showToast({
|
|
|
|
|
- title: error?.message || '创建支付分订单失败',
|
|
|
|
|
- icon: 'none',
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 用户点击按钮 → 直接触发 wx.openBusinessView
|
|
|
|
|
- * 此函数由 button @click 同步调用,满足微信的用户手势要求
|
|
|
|
|
|
|
+ * 预创建支付分订单 → 直接拉起官方确认页
|
|
|
|
|
+ * 使用 uni.request 回调方式,避免 async/await 打破手势链
|
|
|
*/
|
|
*/
|
|
|
-const invokePayScore = () => {
|
|
|
|
|
- if (authBusy.value) return;
|
|
|
|
|
- authBusy.value = true;
|
|
|
|
|
-
|
|
|
|
|
- const pkg = authPackage.value;
|
|
|
|
|
-
|
|
|
|
|
- logger.log('[支付分] invokePayScore, package 长度:', pkg?.length);
|
|
|
|
|
-
|
|
|
|
|
- if (!pkg) {
|
|
|
|
|
- authBusy.value = false;
|
|
|
|
|
- uni.showModal({
|
|
|
|
|
- title: '参数异常',
|
|
|
|
|
- content: 'package 为空,请重新扫码',
|
|
|
|
|
- showCancel: false,
|
|
|
|
|
- });
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const preCreateAndOpenBusinessView = (deviceId: string) => {
|
|
|
|
|
+ busy.value = true;
|
|
|
|
|
+ uni.showLoading({ title: '准备中...', mask: true });
|
|
|
|
|
|
|
|
- wx.openBusinessView({
|
|
|
|
|
- businessType: 'wxpayScoreUse',
|
|
|
|
|
- extraData: {
|
|
|
|
|
- package: pkg,
|
|
|
|
|
- },
|
|
|
|
|
- success: () => {
|
|
|
|
|
- // 用户从支付分页面返回,但不确定是确认还是取消
|
|
|
|
|
- // 轮询后端查支付分订单状态来判断
|
|
|
|
|
- logger.log('[支付分] 从支付分页面返回,开始轮询确认状态');
|
|
|
|
|
- pollPayScoreStatus();
|
|
|
|
|
|
|
+ uni.request({
|
|
|
|
|
+ url: API_CONFIG.baseUrl + '/payscore/pre-create',
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ header: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'accessToken': getToken()
|
|
|
},
|
|
},
|
|
|
- fail: (err: any) => {
|
|
|
|
|
- authBusy.value = false;
|
|
|
|
|
- const errMsg = err?.errMsg || JSON.stringify(err);
|
|
|
|
|
- logger.error('[支付分] openBusinessView fail:', errMsg);
|
|
|
|
|
|
|
+ data: { deviceId },
|
|
|
|
|
+ success: (apiRes: any) => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+
|
|
|
|
|
+ const body = apiRes.data;
|
|
|
|
|
+ if (body.code !== 200 && body.code !== 0) {
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ uni.showToast({ title: body.message || '创建失败', icon: 'none' });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (errMsg.includes('cancel')) {
|
|
|
|
|
|
|
+ const data = body.data;
|
|
|
|
|
+ if (!data || !data.package) {
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ uni.showToast({ title: data?.errorMsg || '创建支付分订单失败', icon: 'none' });
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- uni.showModal({
|
|
|
|
|
- title: '调起支付分失败',
|
|
|
|
|
- content: errMsg,
|
|
|
|
|
- showCancel: false,
|
|
|
|
|
|
|
+ logger.log('[支付分] 预创建成功, 直接拉起官方授权页');
|
|
|
|
|
+
|
|
|
|
|
+ // 记录信息供轮询使用
|
|
|
|
|
+ pollingDeviceId = deviceId;
|
|
|
|
|
+ pollingOutOrderNo = data.outOrderNo;
|
|
|
|
|
+
|
|
|
|
|
+ // 在 uni.request 的 success 回调中调用 openBusinessView
|
|
|
|
|
+ // 这里是原生回调,仍处于用户手势上下文中
|
|
|
|
|
+ wx.openBusinessView({
|
|
|
|
|
+ businessType: 'wxpayScoreUse',
|
|
|
|
|
+ extraData: {
|
|
|
|
|
+ package: data.package,
|
|
|
|
|
+ },
|
|
|
|
|
+ success: () => {
|
|
|
|
|
+ logger.log('[支付分] 从授权页返回,开始轮询确认状态');
|
|
|
|
|
+ startPolling();
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: (err: any) => {
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ const errMsg = err?.errMsg || JSON.stringify(err);
|
|
|
|
|
+ logger.error('[支付分] openBusinessView fail:', errMsg);
|
|
|
|
|
+ if (!errMsg.includes('cancel')) {
|
|
|
|
|
+ uni.showModal({
|
|
|
|
|
+ title: '调起支付分失败',
|
|
|
|
|
+ content: errMsg,
|
|
|
|
|
+ showCancel: false,
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
});
|
|
});
|
|
|
},
|
|
},
|
|
|
|
|
+ fail: (err: any) => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ logger.error('[支付分] API 请求失败', err);
|
|
|
|
|
+ uni.showToast({ title: '网络异常,请重试', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 轮询支付分订单状态,判断用户确认还是取消
|
|
|
|
|
- * DOING = 用户已确认,CREATED = 用户取消/未操作
|
|
|
|
|
|
|
+ * 轮询后端确认用户是否在授权页点了"确认"
|
|
|
*/
|
|
*/
|
|
|
-const pollPayScoreStatus = () => {
|
|
|
|
|
|
|
+const startPolling = () => {
|
|
|
uni.showLoading({ title: '确认结果...', mask: true });
|
|
uni.showLoading({ title: '确认结果...', mask: true });
|
|
|
|
|
|
|
|
- const outOrderNo = authOutOrderNo.value;
|
|
|
|
|
let attempts = 0;
|
|
let attempts = 0;
|
|
|
const maxAttempts = 10;
|
|
const maxAttempts = 10;
|
|
|
- const interval = 1000; // 1s
|
|
|
|
|
|
|
|
|
|
if (pollTimer) clearInterval(pollTimer);
|
|
if (pollTimer) clearInterval(pollTimer);
|
|
|
|
|
|
|
|
pollTimer = setInterval(async () => {
|
|
pollTimer = setInterval(async () => {
|
|
|
attempts++;
|
|
attempts++;
|
|
|
try {
|
|
try {
|
|
|
- const res = await queryPayscoreByOutNo(outOrderNo);
|
|
|
|
|
|
|
+ const res = await queryPayscoreByOutNo(pollingOutOrderNo);
|
|
|
const state = res?.state;
|
|
const state = res?.state;
|
|
|
|
|
|
|
|
logger.log(`[支付分] 轮询第 ${attempts} 次, state:`, state);
|
|
logger.log(`[支付分] 轮询第 ${attempts} 次, state:`, state);
|
|
|
|
|
|
|
|
if (state === 'DOING') {
|
|
if (state === 'DOING') {
|
|
|
- // 用户已确认
|
|
|
|
|
clearPollTimer();
|
|
clearPollTimer();
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
- authReady.value = false;
|
|
|
|
|
- authBusy.value = false;
|
|
|
|
|
- logger.log('[支付分] 用户已确认,开始开门');
|
|
|
|
|
- doOpenDoor(authDeviceId.value);
|
|
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ logger.log('[支付分] 用户已确认,开门');
|
|
|
|
|
+ doOpenDoor(pollingDeviceId);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (attempts >= maxAttempts) {
|
|
if (attempts >= maxAttempts) {
|
|
|
- // 超时未确认,视为取消
|
|
|
|
|
clearPollTimer();
|
|
clearPollTimer();
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
- authBusy.value = false;
|
|
|
|
|
- logger.log('[支付分] 轮询超时,用户未确认');
|
|
|
|
|
|
|
+ busy.value = false;
|
|
|
|
|
+ logger.log('[支付分] 轮询超时,用户取消或未确认');
|
|
|
}
|
|
}
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
logger.error('[支付分] 轮询异常', e);
|
|
logger.error('[支付分] 轮询异常', e);
|
|
|
if (attempts >= maxAttempts) {
|
|
if (attempts >= maxAttempts) {
|
|
|
clearPollTimer();
|
|
clearPollTimer();
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
- authBusy.value = false;
|
|
|
|
|
|
|
+ busy.value = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }, interval);
|
|
|
|
|
|
|
+ }, 1000);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const clearPollTimer = () => {
|
|
const clearPollTimer = () => {
|
|
@@ -283,18 +255,10 @@ const clearPollTimer = () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const cancelAuth = () => {
|
|
|
|
|
- clearPollTimer();
|
|
|
|
|
- authReady.value = false;
|
|
|
|
|
- authBusy.value = false;
|
|
|
|
|
- logger.log('[支付分] 用户取消,返回扫码');
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const doOpenDoor = async (deviceId: string) => {
|
|
|
|
|
|
|
+const doOpenDoor = (deviceId: string) => {
|
|
|
uni.showLoading({ title: '正在开门...', mask: true });
|
|
uni.showLoading({ title: '正在开门...', mask: true });
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- const response = await scanDoor(deviceId);
|
|
|
|
|
|
|
+ scanDoor(deviceId).then(response => {
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
uni.showToast({ title: '开门成功', icon: 'success' });
|
|
uni.showToast({ title: '开门成功', icon: 'success' });
|
|
|
|
|
|
|
@@ -306,10 +270,10 @@ const doOpenDoor = async (deviceId: string) => {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
uni.navigateTo({ url: '/pages/shopping/shopping' });
|
|
uni.navigateTo({ url: '/pages/shopping/shopping' });
|
|
|
}, 1000);
|
|
}, 1000);
|
|
|
- } catch (error: any) {
|
|
|
|
|
|
|
+ }).catch((error: any) => {
|
|
|
uni.hideLoading();
|
|
uni.hideLoading();
|
|
|
logger.error('开门失败:', error);
|
|
logger.error('开门失败:', error);
|
|
|
- }
|
|
|
|
|
|
|
+ });
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const goToMy = () => uni.navigateTo({ url: '/pages/my/my' })
|
|
const goToMy = () => uni.navigateTo({ url: '/pages/my/my' })
|
|
@@ -358,7 +322,6 @@ const onContactSuccess = () => logger.log('[首页] 客服会话已打开')
|
|
|
padding: $spacing-xl 0;
|
|
padding: $spacing-xl 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 扫码按钮 */
|
|
|
|
|
.scan-button {
|
|
.scan-button {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
width: 400rpx;
|
|
width: 400rpx;
|
|
@@ -375,10 +338,13 @@ const onContactSuccess = () => logger.log('[首页] 客服会话已打开')
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
box-sizing: border-box;
|
|
box-sizing: border-box;
|
|
|
flex-shrink: 0;
|
|
flex-shrink: 0;
|
|
|
- line-height: 1;
|
|
|
|
|
|
|
|
|
|
&::after { border: none; }
|
|
&::after { border: none; }
|
|
|
|
|
|
|
|
|
|
+ &[disabled] {
|
|
|
|
|
+ opacity: 0.9;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
&-inner {
|
|
&-inner {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
height: 100%;
|
|
height: 100%;
|
|
@@ -427,78 +393,6 @@ const onContactSuccess = () => logger.log('[首页] 客服会话已打开')
|
|
|
letter-spacing: 4rpx;
|
|
letter-spacing: 4rpx;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 授权按钮 */
|
|
|
|
|
-.auth-button {
|
|
|
|
|
- width: 400rpx;
|
|
|
|
|
- height: 400rpx;
|
|
|
|
|
- min-width: 400rpx;
|
|
|
|
|
- max-width: 400rpx;
|
|
|
|
|
- min-height: 400rpx;
|
|
|
|
|
- max-height: 400rpx;
|
|
|
|
|
- border-radius: 50%;
|
|
|
|
|
- background: transparent;
|
|
|
|
|
- border: none;
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- line-height: 1;
|
|
|
|
|
-
|
|
|
|
|
- &::after { border: none; }
|
|
|
|
|
-
|
|
|
|
|
- &-inner {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- border-radius: 50%;
|
|
|
|
|
- background: linear-gradient(135deg, #07C160 0%, #06AD56 100%);
|
|
|
|
|
- box-shadow: 0 8rpx 32rpx rgba(7, 193, 96, 0.35);
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
-
|
|
|
|
|
- &:active {
|
|
|
|
|
- transform: scale(0.95);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &[disabled] .auth-button-inner {
|
|
|
|
|
- opacity: 0.7;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.auth-btn-icon {
|
|
|
|
|
- width: 100rpx;
|
|
|
|
|
- height: 100rpx;
|
|
|
|
|
- margin-bottom: $spacing-sm;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.auth-btn-text {
|
|
|
|
|
- font-size: 36rpx;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #fff;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.auth-btn-sub {
|
|
|
|
|
- font-size: 22rpx;
|
|
|
|
|
- color: rgba(255, 255, 255, 0.8);
|
|
|
|
|
- margin-top: 8rpx;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/* 取消授权 */
|
|
|
|
|
-.cancel-auth-wrap {
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- margin-top: -$spacing-lg;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.cancel-auth-link {
|
|
|
|
|
- font-size: 26rpx;
|
|
|
|
|
- color: $color-text-secondary;
|
|
|
|
|
- padding: $spacing-sm $spacing-lg;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
/* ========== 快捷功能区 ========== */
|
|
/* ========== 快捷功能区 ========== */
|
|
|
.quick-actions {
|
|
.quick-actions {
|
|
|
display: flex;
|
|
display: flex;
|