ow
This commit is contained in:
1 parent
3194f98ac0
commit
e740ec77ec
24 files changed
+1561
-65
No files matched your search
@@ -20,6 +20,11 @@ defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 自定义返回动作(u-navbar customBack 透传):页面做无栈兜底跳转时用 */
|
||||
customBack: {
|
||||
type: Function as PropType<() => void>,
|
||||
default: undefined,
|
||||
},
|
||||
customStyle: {
|
||||
type: [String, Object] as PropType<string | Record<string, any>>,
|
||||
default: "",
|
||||
@@ -40,11 +45,9 @@ const background = reactive({
|
||||
<template>
|
||||
<view class="app-page" :class="{ 'has-tabbar': showTabbar }" :style="$u.toStyle(customStyle)">
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<u-navbar
|
||||
v-if="!hideNav" :is-back="showNavBack && !showTabbar" :title="navTitle" :background="background" :is-fixed="true"
|
||||
:immersive="false" back-icon-name="arrow-leftward" title-width="350" title-color="#ffffff"
|
||||
back-icon-color="#ffffff"
|
||||
/>
|
||||
<u-navbar v-if="!hideNav" :is-back="showNavBack && !showTabbar" :title="navTitle" :background="background"
|
||||
:is-fixed="true" :immersive="false" :custom-back="customBack" back-icon-name="arrow-leftward" title-width="350"
|
||||
title-color="#ffffff" back-icon-color="#ffffff" />
|
||||
<!-- #endif -->
|
||||
<u-transition name="slide-left" :appear="true">
|
||||
<slot />
|
||||
@@ -55,21 +58,21 @@ const background = reactive({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
// padding-bottom: 30rpx;
|
||||
overflow-y: auto;
|
||||
background-color: $u-bg-white;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: $u-main-color;
|
||||
transition: background 0.3s ease;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
// padding-bottom: 30rpx;
|
||||
overflow-y: auto;
|
||||
background-color: $u-bg-white;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: $u-main-color;
|
||||
transition: background 0.3s ease;
|
||||
|
||||
&.has-tabbar {
|
||||
background-image: linear-gradient(135deg,
|
||||
rgba(var(--u-type-primary-rgb, 41, 121, 255), 0.04) 0%,
|
||||
rgba(var(--u-type-success-rgb, 25, 190, 107), 0.04) 40%,
|
||||
rgba(var(--u-type-warning-rgb, 255, 153, 0), 0.04) 100%);
|
||||
}
|
||||
&.has-tabbar {
|
||||
background-image: linear-gradient(135deg,
|
||||
rgba(var(--u-type-primary-rgb, 41, 121, 255), 0.04) 0%,
|
||||
rgba(var(--u-type-success-rgb, 25, 190, 107), 0.04) 40%,
|
||||
rgba(var(--u-type-warning-rgb, 255, 153, 0), 0.04) 100%);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 新建操作面板:点悬浮「+」弹出的底部抽屉,只两项——上传文件 / 新建文件夹
|
||||
* (对应旧系统 OperatorStation 的 UploadOutlined + FolderAddOutlined 能力)。
|
||||
* 组件只渲染与派发 action,真实上传/建目录由页面接 DMS 接口。
|
||||
*/
|
||||
import { useLocale } from "uview-pro";
|
||||
import { computed } from "vue";
|
||||
|
||||
interface AddAction {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
defineProps({
|
||||
/** 面板是否展开 */
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
/** 抽屉关闭(遮罩/下滑) */
|
||||
(e: "close"): void;
|
||||
/** 点了某项新建动作 */
|
||||
(e: "action", key: string): void;
|
||||
}>();
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
// computed:切换语言后文案跟随重算(tab 页组件实例常驻,setup 只跑一次)
|
||||
const actions = computed<AddAction[]>(() => [
|
||||
{ key: "upload", label: t("FilePage.addUpload"), icon: "arrow-up-fill" },
|
||||
{ key: "folder", label: t("FilePage.addFolder"), icon: "plus-circle-fill" },
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- u-popup 只认 modelValue(v-model),绑 :show 会静默弹不出 -->
|
||||
<u-popup :model-value="visible" mode="bottom" round="24" @close="emit('close')">
|
||||
<view class="file-add-sheet">
|
||||
<text class="file-add-sheet__title">
|
||||
{{ t("FilePage.addTitle") }}
|
||||
</text>
|
||||
<view v-for="action in actions" :key="action.key" class="file-add-sheet__row" @tap="emit('action', action.key)">
|
||||
<u-icon :name="action.icon" size="40" color="#2b8fff" />
|
||||
<text class="file-add-sheet__row-text">
|
||||
{{ action.label }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="file-add-sheet__safe" />
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.file-add-sheet {
|
||||
padding: 40rpx 32rpx 0;
|
||||
background-color: #ffffff;
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
padding: 0 8rpx 24rpx;
|
||||
font-size: 26rpx;
|
||||
color: #8f959e;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
padding: 30rpx 32rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: #f5f6f8;
|
||||
}
|
||||
|
||||
&__row-text {
|
||||
font-size: 30rpx;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
/* 底部留白:贴屏安全区(H5 无 env 时也有 32rpx 呼吸) */
|
||||
&__safe {
|
||||
height: calc(32rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -16,6 +16,11 @@ const props = defineProps({
|
||||
type: Array as PropType<PathNode[]>,
|
||||
default: () => [],
|
||||
},
|
||||
/** 只有根一段时也渲染(传输页目标目录用):文件页惯例是根目录不显示面包屑,默认关 */
|
||||
showSingle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -112,7 +117,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view v-if="items.length > 1" class="file-breadcrumb">
|
||||
<view v-if="items.length > 1 || (showSingle && items.length === 1)" class="file-breadcrumb">
|
||||
<text class="file-breadcrumb__root" @tap="onSegmentTap({ node: items[0], index: 0, ellipsis: false })">
|
||||
{{ items[0].displayName }}
|
||||
</text>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 分类标签筛选:横向标签(全部/图片/视频/文档/音频)+ 右侧「列表视图切换」「多选」按钮。
|
||||
* 分类标签筛选:横向标签(全部/图片/视频/文档/音频)+ 右侧「新建文件夹」「列表视图切换」「多选」按钮。
|
||||
* 标签内容由页面传入(翻译在页面做);当前选中、视图模式、多选态都是外部状态,
|
||||
* 组件只上报用户意图(change / toggle-view / toggle-select),自身不改任何东西。
|
||||
*/
|
||||
import type { PropType } from "vue";
|
||||
import type { FileTabItem } from "@/data/custom/fileBrowser";
|
||||
import { folderGlyph } from "@/utils/folderGlyph";
|
||||
import { selectGlyph } from "@/utils/selectGlyph";
|
||||
import { sortGlyph } from "@/utils/sortGlyph";
|
||||
|
||||
defineProps({
|
||||
/** 分类标签列表 */
|
||||
@@ -35,7 +38,15 @@ const emit = defineEmits<{
|
||||
(e: "sort"): void;
|
||||
(e: "toggle-view"): void;
|
||||
(e: "toggle-select"): void;
|
||||
(e: "new-folder"): void;
|
||||
}>();
|
||||
|
||||
/* 多选开关的自绘字形(用户在 iconfont 挑选的方框+箭头):颜色固定,模块级生成一次 */
|
||||
const selectIconDark = selectGlyph("#1f2329");
|
||||
/* 新建文件夹的自绘字形(用户挑选的文件夹+加号):与「+」直传拆分后的专属入口 */
|
||||
const folderIconDark = folderGlyph("#1f2329");
|
||||
/* 排序的自绘字形(用户挑选的三横线+下箭头):替换原 level 字体图标 */
|
||||
const sortIconDark = sortGlyph("#1f2329");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -49,18 +60,22 @@ const emit = defineEmits<{
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="file-tab-filter__tools">
|
||||
<!-- 排序(从页面导航栏迁来,倒数第3位):level 阶梯横线,比原 order 更有排序感 -->
|
||||
<!-- 新建文件夹:直接弹命名对话框(上传已从悬浮「+」拆分,这里只管建目录) -->
|
||||
<view class="file-tab-filter__tool" @tap="emit('new-folder')">
|
||||
<image class="file-tab-filter__tool-img--folder" :src="folderIconDark" mode="aspectFit" />
|
||||
</view>
|
||||
<!-- 排序(从页面导航栏迁来):自绘三横线+下箭头,比原 level 更有降序感 -->
|
||||
<view class="file-tab-filter__tool" @tap="emit('sort')">
|
||||
<u-icon name="level" size="36" color="#1f2329" />
|
||||
<image class="file-tab-filter__tool-img--sort" :src="sortIconDark" mode="aspectFit" />
|
||||
</view>
|
||||
<!-- 显示的是「点后会切到什么」:网格态给列表图标,列表态给网格图标 -->
|
||||
<view class="file-tab-filter__tool" @tap="emit('toggle-view')">
|
||||
<u-icon :name="viewMode === 'grid' ? 'list' : 'grid-fill'" size="36" color="#1f2329" />
|
||||
</view>
|
||||
<!-- 多选开关:两个图标互切——未进入给勾选圆,进入后给关闭圆(高亮蓝) -->
|
||||
<!-- 多选开关:未进入给自绘方框箭头字形,进入后给关闭圆(高亮蓝) -->
|
||||
<view class="file-tab-filter__tool" @tap="emit('toggle-select')">
|
||||
<u-icon :name="selectMode ? 'close-circle' : 'checkmark-circle'" size="36"
|
||||
:color="selectMode ? '#2b8fff' : '#1f2329'" />
|
||||
<image v-if="!selectMode" class="file-tab-filter__tool-img" :src="selectIconDark" mode="aspectFit" />
|
||||
<u-icon v-else name="close-circle" size="36" color="#2b8fff" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -87,8 +102,8 @@ const emit = defineEmits<{
|
||||
.file-tab-filter__tabs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding-left: 20rpx;
|
||||
gap: 8rpx;
|
||||
padding-left: 4rpx;
|
||||
}
|
||||
|
||||
.file-tab-filter__tab {
|
||||
@@ -120,4 +135,22 @@ const emit = defineEmits<{
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
/* 自绘多选字形:与同行 u-icon size=36 对齐 */
|
||||
.file-tab-filter__tool-img {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
}
|
||||
|
||||
/* 排序字形:原图 viewBox 1178×1024 非正方形,按 1.15:1 给宽高保持视觉重量 */
|
||||
.file-tab-filter__tool-img--sort {
|
||||
width: 38rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
/* 新建文件夹字形:原图内容只占 viewBox 约 78%(四周留白多),放大补偿到与旁边同视觉大小 */
|
||||
.file-tab-filter__tool-img--folder {
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,9 @@
|
||||
* 悬浮操作按钮:蓝色渐变「+」,可在屏幕内自由拖动,松手后位置写入 Storage 下次启动恢复。
|
||||
* 只做外观与点击上报;新建/上传等动作语义由页面处理。
|
||||
* 拖动实现:touch 事件(真机/App)+ mouse 事件(H5 桌面调试)双轨;
|
||||
* 位移小于阈值视为轻点(emit click),超过阈值才算拖动(touch 后屏蔽 mouse 兼容事件防双触发)。
|
||||
* 位移小于阈值视为轻点、超过才算拖动。点击上报走原生 click(onTap)而非 touchend/mouseup
|
||||
* 手动 emit:保留浏览器用户激活链,否则轻点里同步拉起文件选择器等 gesture API 会被静默拦截;
|
||||
* 拖动收尾置 suppressClick 吞掉随后的原生 click,防拖完误触。
|
||||
*/
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
@@ -90,6 +92,9 @@ function onDragMove(x: number, y: number): void {
|
||||
pos.value = clampPos(originPos.x + dx, originPos.y + dy);
|
||||
}
|
||||
|
||||
/** 拖动收尾后浏览器还会补发一次原生 click,置位吞掉它(轻点不置位,由 onTap 正常上报) */
|
||||
let suppressClick = false;
|
||||
|
||||
function onDragEnd(): void {
|
||||
if (!dragging) {
|
||||
return;
|
||||
@@ -97,10 +102,17 @@ function onDragEnd(): void {
|
||||
dragging = false;
|
||||
if (moved) {
|
||||
uni.setStorageSync(STORAGE_KEY, pos.value);
|
||||
suppressClick = true;
|
||||
}
|
||||
else {
|
||||
emit("click");
|
||||
}
|
||||
|
||||
/** 唯一点击出口:原生 click(鼠标轻点/触屏补发)保留用户手势,页面才能在里面拉起文件选择器 */
|
||||
function onTap(): void {
|
||||
if (suppressClick) {
|
||||
suppressClick = false;
|
||||
return;
|
||||
}
|
||||
emit("click");
|
||||
}
|
||||
|
||||
// ===== touch(真机 / App)=====
|
||||
@@ -128,7 +140,7 @@ function onMouseDown(e: MouseEvent): void {
|
||||
if (touchHandled) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
// 注意不能 preventDefault:它会取消后续原生 click 及其用户激活,onTap 就再也收不到点击
|
||||
onDragStart(e.clientX, e.clientY);
|
||||
const move = (ev: MouseEvent) => onDragMove(ev.clientX, ev.clientY);
|
||||
const up = () => {
|
||||
@@ -143,7 +155,7 @@ function onMouseDown(e: MouseEvent): void {
|
||||
|
||||
<template>
|
||||
<view class="float-add-btn" :style="posStyle" @touchstart="onTouchStart" @touchmove.stop.prevent="onTouchMove"
|
||||
@touchend="onTouchEnd" @mousedown="onMouseDown">
|
||||
@touchend="onTouchEnd" @mousedown="onMouseDown" @click="onTap">
|
||||
<u-icon name="plus" size="52" color="#ffffff" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 新建文件夹命名对话框:居中卡片(标题 + 输入 + 取消/创建),
|
||||
* 只负责收集名称——非法字符校验、CreateDmsFolder 接口与结果提示由页面分流。
|
||||
* 提交成功后由父级收起 visible;submitting 期间禁用按钮防连点。
|
||||
*/
|
||||
import { useLocale } from "uview-pro";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
/** 对话框是否展开 */
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** 创建请求在途:置灰两个按钮 */
|
||||
submitting: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
/** 取消/遮罩关闭 */
|
||||
(e: "close"): void;
|
||||
/** 点了创建且名称非空 */
|
||||
(e: "confirm", name: string): void;
|
||||
}>();
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
const name = ref("");
|
||||
|
||||
/** 空白名不算可提交 */
|
||||
const canSubmit = computed(() => name.value.trim().length > 0);
|
||||
|
||||
// 每次展开清掉上次的残留输入(对话框实例常驻 tab 页)
|
||||
watch(
|
||||
() => props.visible,
|
||||
(on) => {
|
||||
if (on) {
|
||||
name.value = "";
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function onConfirm(): void {
|
||||
if (!props.submitting && canSubmit.value) {
|
||||
emit("confirm", name.value.trim());
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- u-popup 只认 modelValue(v-model);提交中禁点遮罩防误关 -->
|
||||
<u-popup :model-value="props.visible" mode="center" round="24" :close-on-click-overlay="!props.submitting"
|
||||
@close="emit('close')">
|
||||
<view class="folder-name-dialog">
|
||||
<text class="folder-name-dialog__title">
|
||||
{{ t("FilePage.addFolder") }}
|
||||
</text>
|
||||
<input v-model="name" class="folder-name-dialog__input" :placeholder="t('FilePage.folderPlaceholder')"
|
||||
:maxlength="50" :disabled="props.submitting" confirm-type="done" @confirm="onConfirm">
|
||||
<view class="folder-name-dialog__actions">
|
||||
<view class="folder-name-dialog__btn" @click="emit('close')">
|
||||
<text class="folder-name-dialog__btn-text">
|
||||
{{ t("FilePage.folderCancel") }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="folder-name-dialog__btn folder-name-dialog__btn--primary"
|
||||
:class="{ 'folder-name-dialog__btn--muted': !canSubmit || props.submitting }" @click="onConfirm">
|
||||
<text class="folder-name-dialog__btn-text folder-name-dialog__btn-text--primary">
|
||||
{{ t("FilePage.folderConfirm") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.folder-name-dialog {
|
||||
width: 560rpx;
|
||||
padding: 40rpx 32rpx 32rpx;
|
||||
background-color: #ffffff;
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
padding-bottom: 28rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
border: 2rpx solid #e6e7ea;
|
||||
border-radius: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 32rpx;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 76rpx;
|
||||
border-radius: 999rpx;
|
||||
background-color: #f5f6f8;
|
||||
|
||||
&--primary {
|
||||
background-color: #2b8fff;
|
||||
}
|
||||
|
||||
/* 名称为空或提交中:主按钮置灰(仍可点,由 onConfirm 拦截) */
|
||||
&--muted {
|
||||
background-color: #b9d6ff;
|
||||
}
|
||||
}
|
||||
|
||||
&__btn-text {
|
||||
font-size: 28rpx;
|
||||
color: #5c626b;
|
||||
|
||||
&--primary {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 文件页顶部导航栏:「返回箭头 + 居中标题 + 右侧两个显隐开关」。
|
||||
* 文件页顶部导航栏:「返回箭头 + 居中标题 + 传输入口 + 右侧两个显隐开关」。
|
||||
* 根目录不显示返回(showBack=false);标题两侧等宽占位保证真居中。
|
||||
* 右侧 search/grid 两个图标分别切换页面里搜索框与快捷入口区的显隐,
|
||||
* 点亮(蓝)= 对应区域显示,置灰 = 隐藏;排序按钮在 file-tab-filter 工具区。
|
||||
* 传输图标是跳转入口(带进行中计数角标),不参与显隐切换;字形用自绘 SVG(transferGlyph)。
|
||||
* 纯展示组件:不自己做导航与显隐逻辑,按钮语义一律 emit 给页面决定。
|
||||
* 顶栏配色跟随截图(白底黑字),不并入 app-page 的绿色 u-navbar,故页面用 hide-nav 让位。
|
||||
*/
|
||||
import { computed } from "vue";
|
||||
import { TRANSFER_ACTIVE_COLOR, transferGlyph } from "@/utils/transferGlyph";
|
||||
|
||||
const props = defineProps({
|
||||
/** 页面标题(页面用 t() 翻译好后传进来) */
|
||||
title: {
|
||||
@@ -28,13 +32,22 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/** 进行中上传任务数:>0 时传输图标点亮并挂数字角标 */
|
||||
transferring: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "back"): void;
|
||||
(e: "toggle-search"): void;
|
||||
(e: "toggle-quick"): void;
|
||||
(e: "transfer"): void;
|
||||
}>();
|
||||
|
||||
/** 传输字形:有进行中任务点亮(iconfont 主色蓝),空闲置灰 */
|
||||
const transferIcon = computed(() => transferGlyph(props.transferring ? TRANSFER_ACTIVE_COLOR : "#8f959e"));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -48,6 +61,13 @@ const emit = defineEmits<{
|
||||
{{ props.title }}
|
||||
</text>
|
||||
<view class="page-navbar__side page-navbar__side--right">
|
||||
<!-- 传输列表入口(常显):有进行中任务时点亮 + 数字角标 -->
|
||||
<view class="page-navbar__btn page-navbar__btn--transfer" @tap="emit('transfer')">
|
||||
<image class="page-navbar__transfer-img" :src="transferIcon" mode="aspectFit" />
|
||||
<text v-if="props.transferring" class="page-navbar__badge">
|
||||
{{ props.transferring > 99 ? "99+" : props.transferring }}
|
||||
</text>
|
||||
</view>
|
||||
<!-- 切换搜索框显隐 -->
|
||||
<view class="page-navbar__btn" @tap="emit('toggle-search')">
|
||||
<u-icon name="search" size="38" :color="props.searchOn ? '#2b8fff' : '#8f959e'" />
|
||||
@@ -72,12 +92,12 @@ const emit = defineEmits<{
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* 左右等宽占位(容纳右侧两个按钮):任何状态下标题都严格居中 */
|
||||
/* 左右等宽占位(容纳右侧三个按钮):任何状态下标题都严格居中 */
|
||||
.page-navbar__side {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
width: 148rpx;
|
||||
width: 208rpx;
|
||||
min-height: 64rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -107,6 +127,31 @@ const emit = defineEmits<{
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
/* 传输入口:右上角挂进行中计数角标 */
|
||||
.page-navbar__btn--transfer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 自绘 SVG 传输字形:与同行 u-icon size=38 视觉对齐 */
|
||||
.page-navbar__transfer-img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.page-navbar__badge {
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
right: 0;
|
||||
min-width: 26rpx;
|
||||
padding: 0 6rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 18rpx;
|
||||
line-height: 26rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
background-color: #f0413e;
|
||||
}
|
||||
|
||||
.page-navbar__title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
Reference in new issue
Block a user