|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,11 @@ |
|||
<script setup lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div>Mobile Preview</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
|||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,22 @@ |
|||
import { ref, computed } from 'vue'; |
|||
|
|||
/** |
|||
* 消息未读数(跨 tabbar 页面共享) |
|||
* - 模块级单例,四个 tabbar 页面(首页/查询/消息/我的)共享同一份 |
|||
* - 消息中心页面负责写入;其他页面仅读取用于 footer-bar 角标展示 |
|||
*/ |
|||
export const messageUnread = ref(0); |
|||
|
|||
/** 格式化为角标展示值(0 显示空) */ |
|||
export const messageUnreadBadge = computed(() => (messageUnread.value > 0 ? messageUnread.value : '')); |
|||
|
|||
/** 直接设置未读总数 */ |
|||
export const setMessageUnread = (count) => { |
|||
messageUnread.value = Number(count) || 0; |
|||
}; |
|||
|
|||
// 占位 default 导出:src/store 目录会被 globalStore.js 通过 import.meta.glob
|
|||
// 以 { import: 'default' } 的方式扫描,缺少 default 会触发
|
|||
// "does not provide an export named 'default'" 错误。
|
|||
// 此处导出一个不带 $id 的对象,globalStore 会自动跳过注册,不影响 Pinia。
|
|||
export default {}; |
|||
@ -0,0 +1,42 @@ |
|||
import { baseUrl } from "@/config/env" |
|||
|
|||
const ABSOLUTE_URL_RE = /^https?:\/\//i |
|||
|
|||
const isAbsoluteUrl = (path) => |
|||
ABSOLUTE_URL_RE.test(path) || path.startsWith("blob:") || path.startsWith("data:") |
|||
|
|||
const getApiBase = () => (baseUrl || "").replace(/\/+$/, "") |
|||
|
|||
/** |
|||
* ȥ�� VITE_BASE_URL ����ǰ��֧���ظ�ǰ�����õ�������·������ /profile/2026/... |
|||
*/ |
|||
export const toRelativeFilePath = (path) => { |
|||
if (!path) return "" |
|||
if (isAbsoluteUrl(path)) return path |
|||
|
|||
const prefix = getApiBase() |
|||
let p = path.startsWith("/") ? path : `/${path}` |
|||
|
|||
if (prefix) { |
|||
const normalizedPrefix = prefix.startsWith("/") ? prefix : `/${prefix}` |
|||
while (p === normalizedPrefix || p.startsWith(`${normalizedPrefix}/`)) { |
|||
p = p.slice(normalizedPrefix.length) || "/" |
|||
if (!p.startsWith("/")) p = `/${p}` |
|||
} |
|||
} |
|||
|
|||
return p |
|||
} |
|||
|
|||
/** |
|||
* ƴ��Ϊǰ�˿ɷ���·�����ݵȣ����ظ����ã����� uploader ���ԣ� |
|||
*/ |
|||
export const toFullFileUrl = (path) => { |
|||
if (!path) return "" |
|||
if (isAbsoluteUrl(path)) return path |
|||
|
|||
const prefix = getApiBase() |
|||
const relative = toRelativeFilePath(path) |
|||
if (!prefix) return relative |
|||
return prefix + relative |
|||
} |
|||