Merge branch 'master' of https://git.yunzer.cn/yunzerwebsite/yunzerwebsiteallinone
This commit is contained in:
commit
843d7164f6
66 files changed
+6976
-864
No files matched your search
@@ -1,5 +1,37 @@
|
||||
<script>
|
||||
import { getBaseURL } from '@/api/request.js'
|
||||
import { isLoggedIn } from '@/utils/auth.js'
|
||||
|
||||
const LOGIN_PAGE = '/pages/login/login'
|
||||
// 不需要登录即可停留的页面:登录 / 注册 / 忘记密码 / 人机验证 / 小程序码确认页 / 启动跳板页
|
||||
const PUBLIC_ROUTES = [
|
||||
'pages/login/login',
|
||||
'pages/login/register',
|
||||
'pages/login/forget',
|
||||
'pages/login/geetest-webview',
|
||||
'pages/register/confirm',
|
||||
'pages/index/index'
|
||||
]
|
||||
|
||||
/** 当前页面路由(取不到时返回空串,交给页面级检测兜底) */
|
||||
function currentRoute() {
|
||||
try {
|
||||
const pages = getCurrentPages()
|
||||
if (!pages.length) return ''
|
||||
const cur = pages[pages.length - 1]
|
||||
return (cur && (cur.route || (cur.$page && cur.$page.path))) || ''
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/** 未登录一律回登录页:覆盖「切后台回来」「从其他入口直接进内页」等场景 */
|
||||
function ensureLogin() {
|
||||
const route = currentRoute()
|
||||
if (!route || PUBLIC_ROUTES.indexOf(route) !== -1) return
|
||||
if (isLoggedIn()) return
|
||||
uni.reLaunch({ url: LOGIN_PAGE })
|
||||
}
|
||||
|
||||
export default {
|
||||
onLaunch() {
|
||||
@@ -7,6 +39,7 @@
|
||||
},
|
||||
onShow() {
|
||||
console.log('App Show')
|
||||
ensureLogin()
|
||||
},
|
||||
onHide() {
|
||||
console.log('App Hide')
|
||||
|
||||
@@ -122,6 +122,19 @@ export function loginByMiniapp({ code, phoneCode = '' } = {}) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序端确认注册:网页注册页展示的小程序码扫码进入本页,
|
||||
* 用户点确认后由服务端把 openid 绑定到该注册会话,网页端即可继续注册。
|
||||
* @param {{ scene: string, code: string, phoneCode?: string, appid?: string }} params
|
||||
*/
|
||||
export function confirmMiniappRegister({ scene, code, phoneCode = '', appid = '' } = {}) {
|
||||
return request({
|
||||
url: '/auth/register/mini/confirm',
|
||||
method: 'POST',
|
||||
data: { scene, code, phone_code: phoneCode, appid }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 已登录态下把当前微信 openid 绑定到该账号(静默调用,失败不提示)。
|
||||
* 小程序认证中 / 未开通手机号能力时,一键登录靠这条绑定按 openid 认人。
|
||||
|
||||
@@ -11,6 +11,20 @@ const DEFAULT_PROD_API = 'https://api.yunzer.cn'
|
||||
/**
|
||||
* @returns {string} 去掉末尾斜杠的 baseURL
|
||||
*/
|
||||
/**
|
||||
* 小程序端 baseURL 兜底:微信要求 request 必须走「已配置的 https 合法域名」,
|
||||
* localhost / 127.0.0.1 / 相对路径 / http 明文在体验版与正式版都会直接报
|
||||
* "url not in domain list"。出现这类取值一律回退生产 API(本地调试请用 H5 端,
|
||||
* 或在开发者工具勾选「不校验合法域名」时用真机调试)。
|
||||
*/
|
||||
function sanitizeMiniProgramBase(base) {
|
||||
const b = String(base || '')
|
||||
if (!b || b.startsWith('/') || !/^https:\/\//i.test(b) || /(localhost|127\.0\.0\.1)/i.test(b)) {
|
||||
return DEFAULT_PROD_API
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
export function resolveBaseURL() {
|
||||
let fromEnv = ''
|
||||
try {
|
||||
@@ -24,7 +38,12 @@ export function resolveBaseURL() {
|
||||
}
|
||||
|
||||
if (fromEnv && fromEnv !== 'undefined' && fromEnv !== 'null') {
|
||||
// #ifdef MP
|
||||
return sanitizeMiniProgramBase(String(fromEnv))
|
||||
// #endif
|
||||
// #ifndef MP
|
||||
return String(fromEnv).replace(/\/$/, '')
|
||||
// #endif
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 小程序订阅消息(对应后端 go/controllers/api_mini_subscribe.go)
|
||||
*
|
||||
* 订阅消息是「用户授权 → 服务器主动推给用户」的通道:
|
||||
* 1. getSubscribeTemplates() 取当前可订阅的模板
|
||||
* 2. 用户在微信弹窗里同意后,authorizeSubscribe() 上报,服务器记一次发送机会
|
||||
* 3. 之后业务侧发站内信/审批待办,服务器自动推送到用户微信
|
||||
*/
|
||||
import { request } from '@/api/request.js'
|
||||
|
||||
/** 取可订阅的模板列表(含模板 ID、跳转页面、剩余可发送次数) */
|
||||
export function getSubscribeTemplates() {
|
||||
return request({
|
||||
url: '/api/mini/subscribe/templates',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报授权结果:每授权一次,服务器记一次可发送机会
|
||||
* @param {string[]} templateIds 用户同意的模板 ID 列表
|
||||
*/
|
||||
export function authorizeSubscribe(templateIds) {
|
||||
return request({
|
||||
url: '/api/mini/subscribe/authorize',
|
||||
method: 'post',
|
||||
data: { template_ids: templateIds }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 发一条测试订阅消息(验证模板配置是否正确)
|
||||
* @param {{title?: string, content?: string}} payload
|
||||
*/
|
||||
export function sendTestSubscribeNotice(payload = {}) {
|
||||
return request({
|
||||
url: '/api/mini/subscribe/test',
|
||||
method: 'post',
|
||||
data: payload
|
||||
})
|
||||
}
|
||||
Generated
-39
@@ -4789,9 +4789,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -4812,9 +4809,6 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -4835,9 +4829,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -4858,9 +4849,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -4881,9 +4869,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -4904,9 +4889,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5080,9 +5062,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5096,9 +5075,6 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5112,9 +5088,6 @@
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5128,9 +5101,6 @@
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5144,9 +5114,6 @@
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5160,9 +5127,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -5176,9 +5140,6 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
||||
+573
-611
File diff suppressed because it is too large.
Load diff
@@ -1,52 +1,38 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<image class="logo" src="/static/logo.png"></image>
|
||||
<view class="text-area">
|
||||
<text class="title">{{title}}</text>
|
||||
</view>
|
||||
<view class="boot">
|
||||
<image class="boot-logo" src="/static/logo.png" mode="aspectFit"></image>
|
||||
<text class="boot-text">正在进入…</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: 'Hello'
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { isLoggedIn } from '@/utils/auth.js'
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 启动跳板页:若启动入口指向本页(脚手架默认首页),先做登录检测再分流,
|
||||
* 未登录直接进登录页,已登录进首页(pages/nav/nav)。
|
||||
*/
|
||||
onShow(() => {
|
||||
uni.reLaunch({ url: isLoggedIn() ? '/pages/nav/nav' : '/pages/login/login' })
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
.boot {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 200rpx;
|
||||
width: 200rpx;
|
||||
margin-top: 200rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 50rpx;
|
||||
.boot-logo {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
.boot-text {
|
||||
font-size: 28rpx;
|
||||
color: #8f8f94;
|
||||
}
|
||||
</style>
|
||||
@@ -239,7 +239,12 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
if (isLoggedIn() && !loading.value) load()
|
||||
// 未登录(含后台切回来时令牌被清)直接回登录页,不再停留在首页
|
||||
if (!isLoggedIn()) {
|
||||
uni.reLaunch({ url: '/pages/login/login' })
|
||||
return
|
||||
}
|
||||
if (!loading.value) load()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ import { mpHeadPad } from '@/utils/mpHead.js'
|
||||
const headPad = mpHeadPad()
|
||||
import { getUser, setUser, logout, isLoggedIn, isSSOEnabled, getToken } from '@/utils/auth.js'
|
||||
import { getCurrentUser, logoutApi, logoutUAC } from '@/api/auth.js'
|
||||
import { requestSubscribeNotice } from '@/utils/subscribe.js'
|
||||
import AppTabbar from '@/components/MainTabbar.vue'
|
||||
|
||||
const user = ref(null)
|
||||
@@ -147,6 +148,11 @@ function onMenuTap(item) {
|
||||
uni.navigateTo({ url: '/pages/login/forget' })
|
||||
return
|
||||
}
|
||||
if (item.title === '消息通知') {
|
||||
// 订阅消息授权:用户同意后,服务器才有一次主动推送的机会
|
||||
requestSubscribeNotice()
|
||||
return
|
||||
}
|
||||
uni.showToast({ title: item.title, icon: 'none' })
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<view class="rp-page">
|
||||
<view class="rp-card">
|
||||
<text class="rp-title">确认注册</text>
|
||||
<text class="rp-desc">你正在为电脑端的账号注册完成身份确认。点击确认后,请回到电脑继续填写账号信息。</text>
|
||||
|
||||
<button class="rp-btn" :class="{ disabled: loading }" :disabled="loading" @tap="confirm('')">
|
||||
{{ loading ? '确认中…' : '确认是我本人注册' }}
|
||||
</button>
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button class="rp-btn ghost" :disabled="loading" open-type="getPhoneNumber" @getphonenumber="onPhone">
|
||||
验证手机号并确认(可选)
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<text class="rp-status" :class="{ ok: success, err: !!errorMsg }">{{ statusText }}</text>
|
||||
|
||||
<view class="rp-back" @tap="backHome">
|
||||
<text class="rp-link">返回首页</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 小程序码扫码注册确认页:
|
||||
* 电脑端注册页展示小程序码(scene=注册会话)→ 微信扫码进入本页 →
|
||||
* uni.login 取 code 调 /auth/register/mini/confirm → 电脑端轮询到已确认后继续注册。
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { confirmMiniappRegister } from '@/api/auth.js'
|
||||
|
||||
const scene = ref('')
|
||||
const loading = ref(false)
|
||||
const success = ref(false)
|
||||
const errorMsg = ref('')
|
||||
const statusText = ref('')
|
||||
|
||||
onLoad((options = {}) => {
|
||||
// scene 由小程序码携带,微信会自动做一次 URL 解码
|
||||
scene.value = options.scene || ''
|
||||
if (!scene.value) {
|
||||
errorMsg.value = '缺少会话标识,请回到电脑端重新获取二维码'
|
||||
statusText.value = errorMsg.value
|
||||
}
|
||||
})
|
||||
|
||||
function miniAppId() {
|
||||
try {
|
||||
const info = uni.getAccountInfoSync()
|
||||
return (info && info.miniProgram && info.miniProgram.appId) || ''
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function uniLoginCode() {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (res) => (res && res.code ? resolve(res.code) : reject(new Error('获取登录凭证失败'))),
|
||||
fail: () => reject(new Error('获取登录凭证失败'))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function confirm(phoneCode = '') {
|
||||
if (loading.value) return
|
||||
if (!scene.value) {
|
||||
errorMsg.value = '缺少会话标识,请回到电脑端重新获取二维码'
|
||||
statusText.value = errorMsg.value
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
errorMsg.value = ''
|
||||
statusText.value = '正在确认…'
|
||||
try {
|
||||
const code = await uniLoginCode()
|
||||
await confirmMiniappRegister({ scene: scene.value, code, phoneCode, appid: miniAppId() })
|
||||
success.value = true
|
||||
statusText.value = '确认成功,请回到电脑继续完成注册'
|
||||
uni.showToast({ title: '确认成功', icon: 'success' })
|
||||
} catch (err) {
|
||||
errorMsg.value = (err && err.message) || '确认失败,请返回电脑端重新获取二维码'
|
||||
statusText.value = errorMsg.value
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 手机号快速验证为可选项:未开通或用户拒绝时仍按 openid 完成确认 */
|
||||
function onPhone(e) {
|
||||
const detail = (e && e.detail) || {}
|
||||
const errMsg = detail.errMsg || ''
|
||||
if (errMsg.indexOf('deny') !== -1) {
|
||||
uni.showToast({ title: '已取消手机号授权', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const phoneCode = detail.code && errMsg.indexOf('fail') === -1 ? detail.code : ''
|
||||
confirm(phoneCode)
|
||||
}
|
||||
|
||||
function backHome() {
|
||||
uni.reLaunch({ url: '/pages/index/index' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.rp-page {
|
||||
min-height: 100vh;
|
||||
padding: 48rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
background: #f6f8fb;
|
||||
}
|
||||
.rp-card {
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 48rpx 36rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
.rp-title {
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
}
|
||||
.rp-desc {
|
||||
display: block;
|
||||
margin-top: 16rpx;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.7;
|
||||
color: #6b7280;
|
||||
}
|
||||
.rp-btn {
|
||||
margin-top: 40rpx;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
font-size: 30rpx;
|
||||
color: #ffffff;
|
||||
background: #2563eb;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
.rp-btn.ghost {
|
||||
margin-top: 20rpx;
|
||||
color: #2563eb;
|
||||
background: #ffffff;
|
||||
border: 1rpx solid #2563eb;
|
||||
}
|
||||
.rp-btn.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.rp-status {
|
||||
display: block;
|
||||
margin-top: 28rpx;
|
||||
font-size: 26rpx;
|
||||
color: #6b7280;
|
||||
}
|
||||
.rp-status.ok {
|
||||
color: #16a34a;
|
||||
}
|
||||
.rp-status.err {
|
||||
color: #dc2626;
|
||||
}
|
||||
.rp-back {
|
||||
margin-top: 36rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.rp-link {
|
||||
font-size: 26rpx;
|
||||
color: #2563eb;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* 订阅消息授权助手
|
||||
*
|
||||
* 用法:在需要提醒用户的入口调用一次即可
|
||||
* import { requestSubscribeNotice } from '@/utils/subscribe.js'
|
||||
* await requestSubscribeNotice()
|
||||
*
|
||||
* 说明:
|
||||
* - 微信一次性订阅:用户每同意一次,服务器才有一次推送机会,所以要挑「用户确实
|
||||
* 可能需要收到提醒」的时机调用(比如进入工作台、提交完审批后)。
|
||||
* - 微信限制一次最多弹 3 个模板,这里自动分批。
|
||||
*/
|
||||
import { getSubscribeTemplates, authorizeSubscribe } from '@/api/subscribe.js'
|
||||
|
||||
/** 单次弹窗最多 3 个模板 ID */
|
||||
const MAX_TMPL_PER_CALL = 3
|
||||
|
||||
/**
|
||||
* 拉起微信订阅授权弹窗,并把授权结果上报给服务器
|
||||
* @param {{silent?: boolean, tip?: string}} options
|
||||
* @returns {Promise<{ok: boolean, reason?: string, accepted?: string[]}>}
|
||||
*/
|
||||
export async function requestSubscribeNotice(options = {}) {
|
||||
const silent = !!options.silent
|
||||
// #ifdef MP-WEIXIN
|
||||
let templates = []
|
||||
try {
|
||||
const data = await getSubscribeTemplates()
|
||||
templates = (data && data.list) || []
|
||||
} catch (e) {
|
||||
if (!silent) uni.showToast({ title: '获取订阅模板失败', icon: 'none' })
|
||||
return { ok: false, reason: 'template_fetch_failed' }
|
||||
}
|
||||
|
||||
const tmplIds = templates.map((t) => t.template_id).filter(Boolean)
|
||||
if (!tmplIds.length) {
|
||||
if (!silent) uni.showToast({ title: '暂未配置订阅消息模板', icon: 'none' })
|
||||
return { ok: false, reason: 'no_template' }
|
||||
}
|
||||
|
||||
const accepted = []
|
||||
for (let i = 0; i < tmplIds.length; i += MAX_TMPL_PER_CALL) {
|
||||
const batch = tmplIds.slice(i, i + MAX_TMPL_PER_CALL)
|
||||
let result = {}
|
||||
try {
|
||||
result = await new Promise((resolve, reject) => {
|
||||
uni.requestSubscribeMessage({
|
||||
tmplIds: batch,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
} catch (e) {
|
||||
if (!silent) uni.showToast({ title: '订阅授权失败', icon: 'none' })
|
||||
return { ok: false, reason: 'request_failed' }
|
||||
}
|
||||
batch.forEach((id) => {
|
||||
if (result[id] === 'accept') accepted.push(id)
|
||||
})
|
||||
}
|
||||
|
||||
if (!accepted.length) {
|
||||
if (!silent) uni.showToast({ title: '你取消了订阅授权', icon: 'none' })
|
||||
return { ok: false, reason: 'refuse' }
|
||||
}
|
||||
|
||||
try {
|
||||
await authorizeSubscribe(accepted)
|
||||
} catch (e) {
|
||||
if (!silent) uni.showToast({ title: '授权结果上报失败', icon: 'none' })
|
||||
return { ok: false, reason: 'report_failed' }
|
||||
}
|
||||
|
||||
if (!silent) {
|
||||
uni.showToast({ title: options.tip || '已开启消息提醒', icon: 'success' })
|
||||
}
|
||||
return { ok: true, accepted }
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
if (!silent) uni.showToast({ title: '请在微信小程序中开启消息提醒', icon: 'none' })
|
||||
return { ok: false, reason: 'not_mp' }
|
||||
// #endif
|
||||
}
|
||||
+19
-1
@@ -3,7 +3,25 @@ import uni from '@dcloudio/vite-plugin-uni'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const rootDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
// 新版 Vite / uni 编译器会把配置文件预打包成 CJS 加载,此时 import.meta.url 为 undefined,
|
||||
// fileURLToPath(undefined) 会抛 "The path argument must be of type string. Received undefined"。
|
||||
// 这里做兜底:拿不到模块路径时退回 __dirname / 当前工作目录(构建命令均在 uniapp 目录执行)。
|
||||
function resolveRootDir() {
|
||||
try {
|
||||
const url = typeof import.meta !== 'undefined' ? import.meta.url : ''
|
||||
if (url) return path.dirname(fileURLToPath(url))
|
||||
} catch (e) {
|
||||
/* import.meta.url 不可用时继续兜底 */
|
||||
}
|
||||
try {
|
||||
if (typeof __dirname !== 'undefined') return __dirname
|
||||
} catch (e) {
|
||||
/* 忽略 */
|
||||
}
|
||||
return process.cwd()
|
||||
}
|
||||
|
||||
const rootDir = resolveRootDir()
|
||||
|
||||
export default defineConfig({
|
||||
base: '/h5/',
|
||||
|
||||
Reference in new issue
Block a user