ow
This commit is contained in:
1 parent
b858386e86
commit
3b2ee8523b
28 files changed
+2285
-1496
No files matched your search
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* 底部导航「文件」页:按截图拆解为独立组件(components/ 下各自一个 vue 文件),
|
||||
* 页面只持有状态与数据,经 props 单向下发、事件(emit)上报,组件之间不互相引用:
|
||||
* page-navbar 顶部导航(居中标题;仅子目录态显示返回箭头)
|
||||
* page-navbar 顶部导航(左对齐标题 + 右对齐操作图标;仅子目录态显示返回箭头)
|
||||
* file-breadcrumb 目录面包屑(仅子目录态:左起排列,放不下折成 根+…+尾部段)
|
||||
* search-input 搜索框(v-model 即时过滤,确认键触发服务端搜索)
|
||||
* quick-entry 快捷功能入口(横向滚动图标组)
|
||||
@@ -32,6 +32,7 @@ import dmsFileService from "@/service/master/dmsFileService";
|
||||
import publishAudioService from "@/service/master/publishAudioService";
|
||||
import publishPhotoService from "@/service/master/publishPhotoService";
|
||||
import publishVideoService from "@/service/master/publishVideoService";
|
||||
import { useMediaIntentStore } from "@/stores/mediaIntent";
|
||||
import { useUploadQueueStore } from "@/stores/uploadQueue";
|
||||
import { chooseFiles } from "@/utils/chooseFiles";
|
||||
import { fetchFileBytes, saveFileBytes, toPlayableUrl } from "@/utils/dmsBytes";
|
||||
@@ -40,13 +41,16 @@ import { transferGlyph } from "@/utils/transferGlyph";
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
// 页面底渐变跟随主题(派生逻辑在 composables/useThemeGradient,多页共用)
|
||||
const { themeBackground } = useThemeGradient();
|
||||
// 页面底跟随主题(派生逻辑在 composables/useThemeGradient,多页共用):
|
||||
// 顶部主题色光晕 → 自然过渡到近白内容区,替代整页铺色的灰浊感
|
||||
const { themeGlowBackground } = useThemeGradient();
|
||||
|
||||
const { files, records, loading, errorText, pathStack, atRoot, init, openTrail, retry, openFolder, back, goTo, search } = useDmsFiles();
|
||||
|
||||
// 上传队列(全局 store):入队在本页、胶囊读它的进行中计数、守卫回调消费它的面包屑导航请求
|
||||
const uploadQueue = useUploadQueueStore();
|
||||
// 跨 tab 意图通道:发布面板「新建相册」→ reLaunch 去媒体页自动进创建态
|
||||
const mediaIntent = useMediaIntentStore();
|
||||
|
||||
// 首次显示拉根目录,之后每次回到页面只刷新当前目录(重进 tab 不该丢位置重新拉全链);
|
||||
// 回页末尾消费传输页的面包屑导航请求(reLaunch 重建后恢复到目标目录)
|
||||
@@ -675,6 +679,41 @@ const publishTitle = computed(() => {
|
||||
return publishKind.value === "audio" ? t("FilePage.publishPickAudio") : t("FilePage.publishPickPhoto");
|
||||
});
|
||||
|
||||
/** 确认键按类型叫「发布相册/发布音乐专辑/发布视频专辑」,不再笼统叫「创建」 */
|
||||
const publishConfirmText = computed(() => {
|
||||
if (publishKind.value === "video") {
|
||||
return t("FilePage.publishConfirmVideo");
|
||||
}
|
||||
return publishKind.value === "audio" ? t("FilePage.publishConfirmAudio") : t("FilePage.publishConfirmPhoto");
|
||||
});
|
||||
|
||||
/** 附加「新建」行文案:与确认键同类型口径 */
|
||||
const publishCreateText = computed(() => {
|
||||
if (publishKind.value === "video") {
|
||||
return t("FilePage.publishCreateVideo");
|
||||
}
|
||||
return publishKind.value === "audio" ? t("FilePage.publishCreateAudio") : t("FilePage.publishCreatePhoto");
|
||||
});
|
||||
|
||||
/** 专辑行首图标:与媒体页分段图标同口径 */
|
||||
const publishRowIcon = computed(() =>
|
||||
publishKind.value === "video" ? "play-circle-fill" : publishKind.value === "audio" ? "volume" : "photo",
|
||||
);
|
||||
|
||||
/** 「新建相册」行:关弹层 → 登记创建意图 → 切到媒体 tab(onShow 消费后进创建态) */
|
||||
function goCreateAlbum(): void {
|
||||
publishVisible.value = false;
|
||||
const kindMap: Record<"image" | "video" | "audio", "photo" | "video" | "audio"> = {
|
||||
image: "photo",
|
||||
video: "video",
|
||||
audio: "audio",
|
||||
};
|
||||
mediaIntent.requestCreate(kindMap[publishKind.value]);
|
||||
// 项目无原生 tabBar(自定义 app-tabbar),switchTab 会报 can not switch to no-tabBar page,
|
||||
// 切 tab 与 app-tabbar.onChange 同套路用 reLaunch;意图由媒体页首显回调消费
|
||||
uni.reLaunch({ url: pageUrl("mediaTab") });
|
||||
}
|
||||
|
||||
async function actionPublish(targets: FileItem[]): Promise<void> {
|
||||
const picked = targets.filter(f => f.kind !== "folder");
|
||||
if (!picked.length) {
|
||||
@@ -735,7 +774,7 @@ async function actionPublish(targets: FileItem[]): Promise<void> {
|
||||
if (hasName) {
|
||||
parts.push(code);
|
||||
}
|
||||
return { key: code, label, sub: parts.join(" · ") };
|
||||
return { key: code, label, sub: parts.join(" · "), icon: publishRowIcon.value };
|
||||
});
|
||||
}
|
||||
catch (error: any) {
|
||||
@@ -886,7 +925,7 @@ const transferIconWhite = transferGlyph("#ffffff");
|
||||
弹层 z-index 再高也压不住它,直接隐藏最干净(主流云盘同款交互) -->
|
||||
<app-page :hide-nav="true"
|
||||
:show-tabbar="atRoot && !actionFile && !selectMode && !folderDialogVisible && !renameVisible && !moveVisible && !shareVisible && !publishVisible">
|
||||
<view class="file-page" :style="{ background: themeBackground }">
|
||||
<view class="file-page" :style="{ background: themeGlowBackground }">
|
||||
<!-- 上半屏整体固定,只有文件列表所在的 scroll-view 内部滚动(整页不滚) -->
|
||||
<view class="file-page__head">
|
||||
<page-navbar :title="navTitle" :show-back="!atRoot" :search-on="showSearch" :quick-on="showQuick"
|
||||
@@ -976,9 +1015,10 @@ const transferIconWhite = transferGlyph("#ffffff");
|
||||
<!-- 共享家人:共享大厅式抽屉(群组卡→逐级下钻→「共享到此」),多选文件一次批量共享 -->
|
||||
<folder-share-picker :visible="shareVisible" :selected-count="shareTargets.length" @close="shareVisible = false"
|
||||
@confirm="onShareConfirm" />
|
||||
<!-- 发布:选专辑 -->
|
||||
<!-- 发布:选专辑(确认键按类型叫「发布相册」等;附「新建相册」行跳媒体页创建态) -->
|
||||
<option-picker :visible="publishVisible" :title="publishTitle" :items="publishItems" :loading="publishLoading"
|
||||
:empty-text="t('FilePage.pickerEmpty')" @close="publishVisible = false" @confirm="onPublishConfirm" />
|
||||
:empty-text="t('FilePage.pickerEmpty')" :confirm-text="publishConfirmText" :create-text="publishCreateText"
|
||||
@close="publishVisible = false" @create="goCreateAlbum" @confirm="onPublishConfirm" />
|
||||
<!-- 多选底部操作栏:常驻非模态(无遮罩),勾选与动作可交替进行;
|
||||
动作集是旧系统多选子集——共享/发布按同媒体类型条件,重命名/移动仅单选 -->
|
||||
<view v-if="selectMode" class="file-page__actions">
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -12,11 +12,19 @@
|
||||
import type { FamilyGroupEntity } from "@/data/auto/familyGroupEntity";
|
||||
import { useLocale } from "uview-pro";
|
||||
import { computed, ref } from "vue";
|
||||
import { useAuthGuard, useFamilyGroups, useThemeGradient } from "@/composables";
|
||||
import { useAuthGuard, useFamilyGroups, useThemeGradient, useThemeTokens } from "@/composables";
|
||||
import { useLoginProfileStore } from "@/stores";
|
||||
|
||||
const { t } = useLocale();
|
||||
const { themeBackground } = useThemeGradient();
|
||||
// 主题派生色经 CSS 变量下发(与媒体页同套):头卡/徽章/主按钮/链接全部跟主题
|
||||
const { primary, accentGradient, accentSoft, accentShadow } = useThemeTokens();
|
||||
const themeVars = computed(() => ({
|
||||
"--fg-primary": primary.value,
|
||||
"--fg-gradient": accentGradient.value,
|
||||
"--fg-soft": accentSoft.value,
|
||||
"--fg-shadow": accentShadow.value,
|
||||
}));
|
||||
const profile = useLoginProfileStore();
|
||||
|
||||
const {
|
||||
@@ -74,6 +82,20 @@ const navTitle = computed(() => {
|
||||
return t("SharePage.title");
|
||||
});
|
||||
|
||||
/** 详情区分区卡折叠态(与媒体页同款交互):默认全展开,点标题行切换 */
|
||||
type FoldKey = "info" | "folders" | "requests" | "members" | "permissions";
|
||||
const folded = ref<Record<FoldKey, boolean>>({
|
||||
info: false,
|
||||
folders: false,
|
||||
requests: false,
|
||||
members: false,
|
||||
permissions: false,
|
||||
});
|
||||
|
||||
function toggleFold(key: FoldKey): void {
|
||||
folded.value[key] = !folded.value[key];
|
||||
}
|
||||
|
||||
/** 申请加入入口:非新建、非管理员、非成员,且群开启了「可申请」 */
|
||||
const canApply = computed(() =>
|
||||
!creating.value
|
||||
@@ -291,7 +313,7 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
<template>
|
||||
<!-- 列表态显示 tabbar,进详情(或弹层展开)收起 -->
|
||||
<app-page :hide-nav="true" :show-tabbar="!inDetail && !dialogVisible">
|
||||
<view class="share-page" :style="{ background: themeBackground }">
|
||||
<view class="share-page" :style="[{ background: themeBackground }, themeVars]">
|
||||
<!-- ===== 列表态:公开群 + 我的群 ===== -->
|
||||
<view v-if="!inDetail" class="share-page__body">
|
||||
<view class="share-page__head">
|
||||
@@ -365,42 +387,50 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
<!-- ===== 详情态:群管理 ===== -->
|
||||
<view v-else class="share-page__body">
|
||||
<view class="share-page__head">
|
||||
<page-navbar :title="navTitle" :show-back="true" :show-transfer="false" :show-quick-toggle="false"
|
||||
:show-search-toggle="false" @back="onBack" />
|
||||
<hero-navbar :title="navTitle" @back="onBack" />
|
||||
</view>
|
||||
<view class="share-page__scroll-wrap">
|
||||
<scroll-view scroll-y class="share-page__scroll">
|
||||
<!-- 群信息头卡 -->
|
||||
<!-- 群信息头卡(与媒体页同套):白底 + 主题浅底图标 + 编号灰字独立行 -->
|
||||
<view class="detail-hero">
|
||||
<view class="detail-hero__avatar">
|
||||
<u-icon name="account-fill" size="56" color="#ffffff" />
|
||||
<u-icon name="account-fill" size="64" :color="primary" />
|
||||
</view>
|
||||
<view class="detail-hero__main">
|
||||
<text class="detail-hero__name">
|
||||
{{ detail.FamilyGroup.FamilyLocalName || t("SharePage.unnamed") }}
|
||||
</text>
|
||||
<text class="detail-hero__code">
|
||||
{{ detail.FamilyGroup.FamilyName }}
|
||||
</text>
|
||||
<view class="detail-hero__chips">
|
||||
<text class="group-card__chip group-card__chip--code">
|
||||
{{ detail.FamilyGroup.FamilyName }}
|
||||
</text>
|
||||
<text v-if="detail.IsOpen" class="group-card__chip">
|
||||
<text v-if="detail.IsOpen" class="detail-hero__chip">
|
||||
{{ t("SharePage.chipPublic") }}
|
||||
</text>
|
||||
<text v-if="detail.IsAdd" class="group-card__chip">
|
||||
<text v-if="detail.IsAdd" class="detail-hero__chip">
|
||||
{{ t("SharePage.chipJoinable") }}
|
||||
</text>
|
||||
<text v-if="isManager" class="group-card__chip group-card__chip--admin">
|
||||
<text v-if="isManager" class="detail-hero__chip detail-hero__chip--admin">
|
||||
{{ t("SharePage.chipManager") }}
|
||||
</text>
|
||||
<text v-else-if="isMember" class="group-card__chip">
|
||||
<text v-else-if="isMember" class="detail-hero__chip detail-hero__chip--member">
|
||||
{{ t("SharePage.chipMember") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 修改 / 解散:右上角圆形图标动作(与媒体页同套) -->
|
||||
<view v-if="!isEdit && isManager" class="detail-hero__acts">
|
||||
<view class="detail-hero__act" @tap="onAmend">
|
||||
<u-icon name="edit-pen" size="34" :color="primary" />
|
||||
</view>
|
||||
<view class="detail-hero__act detail-hero__act--danger" @tap="onDissolve">
|
||||
<u-icon name="trash" size="34" color="#f0413e" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 动作栏:按角色/态显示 -->
|
||||
<view class="detail-actions">
|
||||
<!-- 动作栏:编辑态取消/保存;非成员可申请加入(修改/解散已升为头卡图标钮) -->
|
||||
<view v-if="isEdit || canApply" class="detail-actions">
|
||||
<template v-if="isEdit">
|
||||
<view class="detail-actions__btn" @tap="onCancelEdit">
|
||||
<text>{{ t("SharePage.cancel") }}</text>
|
||||
@@ -409,178 +439,198 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
<text>{{ t("SharePage.save") }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-if="isManager" class="detail-actions__btn detail-actions__btn--primary"
|
||||
@tap="onAmend">
|
||||
<text>{{ t("SharePage.amend") }}</text>
|
||||
</view>
|
||||
<view v-if="canApply" class="detail-actions__btn detail-actions__btn--join"
|
||||
@tap="onApplyJoin">
|
||||
<text>{{ t("SharePage.applyJoin") }}</text>
|
||||
</view>
|
||||
<view v-if="isManager" class="detail-actions__btn detail-actions__btn--danger"
|
||||
@tap="onDissolve">
|
||||
<text>{{ t("SharePage.dissolve") }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<!-- 群组信息卡 -->
|
||||
<view class="detail-card">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.groupInfo") }}
|
||||
</text>
|
||||
<view class="detail-field">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.groupName") }}
|
||||
</text>
|
||||
<input v-model="detail.FamilyGroup.FamilyLocalName" class="detail-field__input"
|
||||
:disabled="!isEdit" :maxlength="50" :placeholder="t('SharePage.nameRequired')">
|
||||
</view>
|
||||
<view class="detail-field">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.groupDesc") }}
|
||||
</text>
|
||||
<textarea v-model="detail.FamilyGroup.Notice" class="detail-field__textarea"
|
||||
:disabled="!isEdit" :maxlength="256" :placeholder="t('SharePage.noDesc')" />
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.publicSetting") }}
|
||||
</text>
|
||||
<u-switch :model-value="detail.IsOpen" :disabled="!isEdit"
|
||||
@change="(v: boolean) => detail.IsOpen = v" />
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.joinApply") }}
|
||||
</text>
|
||||
<u-switch :model-value="detail.IsAdd" :disabled="!isEdit"
|
||||
@change="(v: boolean) => detail.IsAdd = v" />
|
||||
<view v-else-if="canApply" class="detail-actions__btn detail-actions__btn--join"
|
||||
@tap="onApplyJoin">
|
||||
<text>{{ t("SharePage.applyJoin") }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 共享目录卡 -->
|
||||
<!-- 群组信息卡:点标题行折叠/展开 -->
|
||||
<view class="detail-card">
|
||||
<view class="detail-card__head">
|
||||
<view class="detail-card__head" @tap="toggleFold('info')">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.groupInfo") }}
|
||||
</text>
|
||||
<u-icon :name="folded.info ? 'arrow-right' : 'arrow-down'" size="26" color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.info">
|
||||
<view class="detail-field">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.groupName") }}
|
||||
</text>
|
||||
<input v-model="detail.FamilyGroup.FamilyLocalName" class="detail-field__input"
|
||||
:disabled="!isEdit" :maxlength="50" :placeholder="t('SharePage.nameRequired')">
|
||||
</view>
|
||||
<view class="detail-field">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.groupDesc") }}
|
||||
</text>
|
||||
<textarea v-model="detail.FamilyGroup.Notice" class="detail-field__textarea"
|
||||
:disabled="!isEdit" :maxlength="256" :placeholder="t('SharePage.noDesc')" />
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.publicSetting") }}
|
||||
</text>
|
||||
<u-switch :model-value="detail.IsOpen" :disabled="!isEdit" :active-color="primary"
|
||||
@change="(v: boolean) => detail.IsOpen = v" />
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">
|
||||
{{ t("SharePage.joinApply") }}
|
||||
</text>
|
||||
<u-switch :model-value="detail.IsAdd" :disabled="!isEdit" :active-color="primary"
|
||||
@change="(v: boolean) => detail.IsAdd = v" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 共享目录卡:点标题行折叠/展开,「新建」钮不触发折叠 -->
|
||||
<view class="detail-card">
|
||||
<view class="detail-card__head" @tap="toggleFold('folders')">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.folders") }}
|
||||
</text>
|
||||
<text v-if="isEdit" class="detail-card__add" @tap="onNewFolder">
|
||||
+ {{ t("SharePage.newFolder") }}
|
||||
</text>
|
||||
</view>
|
||||
<view v-if="!detail.FamilyGroupFolders.length" class="detail-empty">
|
||||
<text>{{ t("SharePage.noFolders") }}</text>
|
||||
</view>
|
||||
<view v-for="(folder, index) in detail.FamilyGroupFolders" :key="folder.FolderId || index"
|
||||
class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
<view class="detail-card__head-acts">
|
||||
<text v-if="isEdit" class="detail-card__add" @tap.stop="onNewFolder">
|
||||
+ {{ t("SharePage.newFolder") }}
|
||||
</text>
|
||||
<u-icon :name="folded.folders ? 'arrow-right' : 'arrow-down'" size="26"
|
||||
color="#8f959e" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-show="!folded.folders">
|
||||
<view v-if="!detail.FamilyGroupFolders.length" class="detail-empty">
|
||||
<text>{{ t("SharePage.noFolders") }}</text>
|
||||
</view>
|
||||
<view v-for="(folder, index) in detail.FamilyGroupFolders"
|
||||
:key="folder.FolderId || index" class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<input v-if="isEdit" v-model="folder.FolderLocalName" class="detail-item__input"
|
||||
:maxlength="50" :placeholder="t('SharePage.folderPh')">
|
||||
<text v-else class="detail-item__name">
|
||||
{{ folder.FolderLocalName || t("SharePage.unnamed") }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<text v-if="!isEdit && folder.IsSharePermission" class="detail-item__link"
|
||||
@tap="onAssignPermission(folder.FolderName)">
|
||||
{{ t("SharePage.assign") }}
|
||||
</text>
|
||||
<text v-if="isEdit" class="detail-item__del" @tap="
|
||||
onRemoveFolder(folder.FolderId, folder.FolderName)
|
||||
">
|
||||
{{ t("SharePage.delete") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<input v-if="isEdit" v-model="folder.Notice" class="detail-item__sub"
|
||||
:maxlength="50" :placeholder="t('SharePage.notePh')">
|
||||
<text v-else-if="folder.Notice" class="detail-item__sub detail-item__sub--text">
|
||||
{{ folder.Notice }}
|
||||
</text>
|
||||
<input v-if="isEdit" v-model="folder.FolderLocalName" class="detail-item__input"
|
||||
:maxlength="50" :placeholder="t('SharePage.folderPh')">
|
||||
<text v-else class="detail-item__name">
|
||||
{{ folder.FolderLocalName || t("SharePage.unnamed") }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<text v-if="!isEdit && folder.IsSharePermission" class="detail-item__link"
|
||||
@tap="onAssignPermission(folder.FolderName)">
|
||||
{{ t("SharePage.assign") }}
|
||||
</text>
|
||||
<text v-if="isEdit" class="detail-item__del" @tap="
|
||||
onRemoveFolder(folder.FolderId, folder.FolderName)
|
||||
">
|
||||
{{ t("SharePage.delete") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<input v-if="isEdit" v-model="folder.Notice" class="detail-item__sub" :maxlength="50"
|
||||
:placeholder="t('SharePage.notePh')">
|
||||
<text v-else-if="folder.Notice" class="detail-item__sub detail-item__sub--text">
|
||||
{{ folder.Notice }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 待审成员(仅管理员)-->
|
||||
<!-- 待审成员(仅管理员):点标题行折叠/展开 -->
|
||||
<view v-if="isManager && detail.FamilyGroupRequests.length" class="detail-card">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.requests") }}
|
||||
</text>
|
||||
<view v-for="(req, index) in detail.FamilyGroupRequests" :key="req.UserName || index"
|
||||
class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text class="detail-item__name">
|
||||
{{ req.UserLocalName || req.UserName }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<text class="detail-item__link" @tap="onApprove(req.UserName)">
|
||||
{{ t("SharePage.approve") }}
|
||||
</text>
|
||||
<text class="detail-item__del" @tap="onReject(req.UserName)">
|
||||
{{ t("SharePage.reject") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="req.Notice" class="detail-item__sub detail-item__sub--text">
|
||||
{{ req.Notice }}
|
||||
<view class="detail-card__head" @tap="toggleFold('requests')">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.requests") }}
|
||||
</text>
|
||||
<u-icon :name="folded.requests ? 'arrow-right' : 'arrow-down'" size="26"
|
||||
color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.requests">
|
||||
<view v-for="(req, index) in detail.FamilyGroupRequests" :key="req.UserName || index"
|
||||
class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text class="detail-item__name">
|
||||
{{ req.UserLocalName || req.UserName }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<text class="detail-item__link" @tap="onApprove(req.UserName)">
|
||||
{{ t("SharePage.approve") }}
|
||||
</text>
|
||||
<text class="detail-item__del" @tap="onReject(req.UserName)">
|
||||
{{ t("SharePage.reject") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="req.Notice" class="detail-item__sub detail-item__sub--text">
|
||||
{{ req.Notice }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 正式成员 -->
|
||||
<!-- 正式成员:点标题行折叠/展开 -->
|
||||
<view v-if="detail.FamilyGroupManagers.length" class="detail-card">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.members") }}
|
||||
</text>
|
||||
<view v-for="(mem, index) in detail.FamilyGroupManagers" :key="mem.UserName || index"
|
||||
class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text class="detail-item__name">
|
||||
{{ mem.UserLocalName || mem.UserName }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<u-switch v-if="isEdit" :model-value="mem.IsManager" size="40"
|
||||
:disabled="mem.UserName === detail.FamilyGroup.CreatedBy"
|
||||
@change="() => toggleManager(mem.UserName)" />
|
||||
<text v-else-if="mem.IsManager"
|
||||
class="group-card__chip group-card__chip--admin">
|
||||
{{ t("SharePage.chipManager") }}
|
||||
<view class="detail-card__head" @tap="toggleFold('members')">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.members") }}
|
||||
</text>
|
||||
<u-icon :name="folded.members ? 'arrow-right' : 'arrow-down'" size="26"
|
||||
color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.members">
|
||||
<view v-for="(mem, index) in detail.FamilyGroupManagers" :key="mem.UserName || index"
|
||||
class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text v-if="isEdit && mem.UserName !== detail.FamilyGroup.CreatedBy"
|
||||
class="detail-item__del" @tap="onRemoveMember(mem.UserName)">
|
||||
{{ t("SharePage.removeMember") }}
|
||||
<text class="detail-item__name">
|
||||
{{ mem.UserLocalName || mem.UserName }}
|
||||
</text>
|
||||
<view class="detail-item__acts">
|
||||
<u-switch v-if="isEdit" :model-value="mem.IsManager" size="40"
|
||||
:active-color="primary"
|
||||
:disabled="mem.UserName === detail.FamilyGroup.CreatedBy"
|
||||
@change="() => toggleManager(mem.UserName)" />
|
||||
<text v-else-if="mem.IsManager"
|
||||
class="detail-hero__chip detail-hero__chip--admin">
|
||||
{{ t("SharePage.chipManager") }}
|
||||
</text>
|
||||
<text v-if="isEdit && mem.UserName !== detail.FamilyGroup.CreatedBy"
|
||||
class="detail-item__del" @tap="onRemoveMember(mem.UserName)">
|
||||
{{ t("SharePage.removeMember") }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 目录权限(仅管理员)-->
|
||||
<!-- 目录权限(仅管理员):点标题行折叠/展开 -->
|
||||
<view v-if="isManager && detail.FamilyGroupPermissions.length" class="detail-card">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.permissions") }}
|
||||
</text>
|
||||
<view v-for="(perm, index) in detail.FamilyGroupPermissions"
|
||||
:key="`${perm.FolderName}-${perm.UserName}-${index}`" class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text class="detail-item__name">
|
||||
{{ perm.FolderLocalName || perm.FolderName }}
|
||||
</text>
|
||||
<text class="detail-item__sub detail-item__sub--inline">
|
||||
{{ perm.UserLocalName || perm.UserName }}
|
||||
</text>
|
||||
<view class="detail-card__head" @tap="toggleFold('permissions')">
|
||||
<text class="detail-card__title">
|
||||
{{ t("SharePage.permissions") }}
|
||||
</text>
|
||||
<u-icon :name="folded.permissions ? 'arrow-right' : 'arrow-down'" size="26"
|
||||
color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.permissions">
|
||||
<view v-for="(perm, index) in detail.FamilyGroupPermissions"
|
||||
:key="`${perm.FolderName}-${perm.UserName}-${index}`" class="detail-item">
|
||||
<view class="detail-item__row">
|
||||
<text class="detail-item__index">
|
||||
{{ index + 1 }}
|
||||
</text>
|
||||
<text class="detail-item__name">
|
||||
{{ perm.FolderLocalName || perm.FolderName }}
|
||||
</text>
|
||||
<text class="detail-item__sub detail-item__sub--inline">
|
||||
{{ perm.UserLocalName || perm.UserName }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -663,8 +713,8 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
padding: 8rpx 28rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 26rpx;
|
||||
color: #2b8fff;
|
||||
background-color: #eaf4ff;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
}
|
||||
|
||||
/* ===== 列表卡片 ===== */
|
||||
@@ -686,7 +736,7 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 20rpx;
|
||||
background: linear-gradient(135deg, #4a9dff, #2b8fff);
|
||||
background: var(--fg-gradient, linear-gradient(135deg, #4a9dff, #2b8fff));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -731,8 +781,8 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
}
|
||||
|
||||
.group-card__chip--code {
|
||||
color: #2b8fff;
|
||||
background-color: #eaf4ff;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
}
|
||||
|
||||
.group-card__chip--admin {
|
||||
@@ -746,25 +796,50 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
color: #bfc3c9;
|
||||
}
|
||||
|
||||
/* ===== 详情头卡 + 动作栏 ===== */
|
||||
/* ===== 详情头卡 + 动作栏(与媒体页同套:白底卡 + 主题点缀) ===== */
|
||||
.detail-hero {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
gap: 28rpx;
|
||||
margin: 0 4rpx 20rpx;
|
||||
padding: 32rpx 28rpx;
|
||||
border-radius: 24rpx;
|
||||
background: linear-gradient(135deg, #4a9dff, #2b8fff);
|
||||
padding: 40rpx 32rpx;
|
||||
border-radius: 32rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
/* 头卡右上角圆形动作钮(同媒体页):修改=浅灰底主题图标,解散=浅红底红图标 */
|
||||
.detail-hero__acts {
|
||||
position: absolute;
|
||||
top: 28rpx;
|
||||
right: 28rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.detail-hero__act {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #f2f3f5;
|
||||
|
||||
&--danger {
|
||||
background-color: #ffeceb;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-hero__avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: 24rpx;
|
||||
background-color: rgba(255, 255, 255, 0.24);
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 32rpx;
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -773,22 +848,48 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.detail-hero__name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2329;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 群编号独立成行:灰字说明(同媒体页专辑编号) */
|
||||
.detail-hero__code {
|
||||
font-size: 26rpx;
|
||||
color: #8f959e;
|
||||
}
|
||||
|
||||
.detail-hero__chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
gap: 12rpx;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
/* 头卡胶囊:公开/可申请=主题浅底主题字,管理员=黄底橙字,成员=浅灰 */
|
||||
.detail-hero__chip {
|
||||
padding: 6rpx 22rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
|
||||
&--admin {
|
||||
color: #ff9500;
|
||||
background-color: #fff4e0;
|
||||
}
|
||||
|
||||
&--member {
|
||||
color: #5c626b;
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-actions {
|
||||
@@ -797,31 +898,32 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
margin: 0 4rpx 20rpx;
|
||||
}
|
||||
|
||||
/* 动作钮统一规格(同媒体页/option-picker):等高圆角矩形 + 细描边,主钮纯色跟主题 */
|
||||
.detail-actions__btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 28rpx;
|
||||
height: 96rpx;
|
||||
border: 2rpx solid #e5e6eb;
|
||||
border-radius: 24rpx;
|
||||
font-size: 32rpx;
|
||||
color: #5c626b;
|
||||
background-color: #ffffff;
|
||||
|
||||
&--primary {
|
||||
border-color: transparent;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
background-color: #2b8fff;
|
||||
background-color: var(--fg-primary, #2b8fff);
|
||||
}
|
||||
|
||||
&--join {
|
||||
border-color: transparent;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
background-color: #21b169;
|
||||
}
|
||||
|
||||
&--danger {
|
||||
color: #f0413e;
|
||||
background-color: #ffeceb;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 分区卡片 ===== */
|
||||
@@ -838,15 +940,22 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 标题行右侧一组:新建钮 + 折叠箭头 */
|
||||
.detail-card__head-acts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28rpx;
|
||||
}
|
||||
|
||||
.detail-card__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.detail-card__add {
|
||||
font-size: 26rpx;
|
||||
color: #2b8fff;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
}
|
||||
|
||||
.detail-field {
|
||||
@@ -871,25 +980,25 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
.detail-item__input,
|
||||
.detail-item__sub {
|
||||
box-sizing: border-box;
|
||||
padding: 0 20rpx;
|
||||
height: 68rpx;
|
||||
padding: 0 24rpx;
|
||||
height: 88rpx;
|
||||
border: 2rpx solid #e6e7ea;
|
||||
border-radius: 14rpx;
|
||||
font-size: 26rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
background-color: #f7f8fa;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.detail-field__textarea {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-height: 120rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
min-height: 200rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border: 2rpx solid #e6e7ea;
|
||||
border-radius: 14rpx;
|
||||
font-size: 26rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1f2329;
|
||||
background-color: #f7f8fa;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.detail-empty {
|
||||
@@ -951,7 +1060,7 @@ function groupDesc(group: FamilyGroupEntity): string {
|
||||
|
||||
.detail-item__link {
|
||||
font-size: 24rpx;
|
||||
color: #2b8fff;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
}
|
||||
|
||||
.detail-item__del {
|
||||
|
||||
Reference in new issue
Block a user