w
This commit is contained in:
1 parent
1c91f62ff6
commit
6710b429b0
3 files changed
+83
-25
No files matched your search
@@ -17,7 +17,7 @@ import { StorageUsageData } from "@/data/auto/storageUsageData";
|
||||
import { useLocale } from "uview-pro";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { brandGlyph } from "@/common/brand";
|
||||
import { buildChunkFileName, uploadFile } from "@/common/http.interceptor";
|
||||
import { buildChunkFileName, requestBuffer, uploadFile } from "@/common/http.interceptor";
|
||||
import { userTypeGlyph, userTypePillBg } from "@/common/userTypeIcons";
|
||||
import { useIdCardVerify, useThemeGradient, useThemeTokens } from "@/composables";
|
||||
import { useArticles } from "@/composables/useArticles";
|
||||
@@ -40,6 +40,7 @@ import dmsFileService from "@/service/master/dmsFileService";
|
||||
import { useLoginProfileStore } from "@/stores";
|
||||
import { pageUrl } from "@/router/routes";
|
||||
import { chooseFiles } from "@/utils/chooseFiles";
|
||||
import { saveFileBytes } from "@/utils/dmsBytes";
|
||||
import { absoluteFileUrl, backupFileUrl } from "@/utils/fileUrl";
|
||||
|
||||
/** ready:组件挂载完成通知(时序口径见文件底部 onMounted 注释) */
|
||||
@@ -128,12 +129,42 @@ const storageBarWidth = computed(() => {
|
||||
const userTypeIcon = computed(() => userTypeGlyph(currentType.value));
|
||||
const userTypeBg = computed(() => userTypePillBg(currentType.value));
|
||||
/** 网盘存储卡图标:内联云形 SVG(同 treeGlyph 套路),绿描边置于柔光圆内(存储卡为浅色渐变描边底) */
|
||||
const cloudGlyph = `data:image/svg+xml,${encodeURIComponent([
|
||||
const cloudSvg = [
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='#2f9e6b' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'>",
|
||||
"<path d='M6.8 18.5a4.3 4.3 0 0 1-.5-8.56 5.6 5.6 0 0 1 10.75-1.06A3.9 3.9 0 0 1 17.4 18.5z'/>",
|
||||
"<path d='M9.5 14.2l1.9 1.9 3.6-3.9'/>",
|
||||
"</svg>",
|
||||
].join(""))}`;
|
||||
].join("");
|
||||
const cloudGlyph = `data:image/svg+xml,${encodeURIComponent(cloudSvg)}`;
|
||||
|
||||
/** 仅 H5 的「下载 App」图标:内联下箭头 SVG(绿描边,放在「网盘存储空间」标题旁),点击从 /FileServer 下载 youjiala.apk */
|
||||
const downloadSvg = [
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='#2f9e6b' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'>",
|
||||
"<path d='M12 3.5v11'/>",
|
||||
"<path d='M7.5 10.5l4.5 4.5 4.5-4.5'/>",
|
||||
"<path d='M5 20.5h14'/>",
|
||||
"</svg>",
|
||||
].join("");
|
||||
const downloadGlyph = `data:image/svg+xml,${encodeURIComponent(downloadSvg)}`;
|
||||
|
||||
// #ifdef H5
|
||||
/** H5 下载 App 安装包:复用网盘 file 页同一条下载链——requestBuffer 按当前线路取字节
|
||||
* (后端报错回的是 JSON,按 content-type 转成错误提示,不会跳错误页),saveFileBytes 走 blob <a download> 落盘 */
|
||||
async function onDownloadApp(): Promise<void> {
|
||||
uni.showLoading({ title: t("storage.downloadingApp"), mask: true });
|
||||
try {
|
||||
const bytes = await requestBuffer({ url: "/FileServer/youjiala.apk", method: "GET" });
|
||||
await saveFileBytes({ bytes, name: "youjiala.apk" });
|
||||
uni.showToast({ title: t("storage.downloadStarted"), icon: "none" });
|
||||
}
|
||||
catch {
|
||||
// requestBuffer 内部已 notifyError 弹示失败原因,这里只收尾
|
||||
}
|
||||
finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
/** 未认证底部弹层:单击「未认证」徽标从底部弹出身份证认证,复用 useIdCardVerify(与身份验证页同一套流程) */
|
||||
const idPopup = ref(false);
|
||||
@@ -1625,9 +1656,14 @@ defineExpose({
|
||||
<image class="home-card__sicon-img" :src="cloudGlyph" mode="aspectFit" />
|
||||
</view>
|
||||
<text class="home-card__stitle">{{ t("storage.title") }}</text>
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="home-card__dlapp" @tap="onDownloadApp">
|
||||
<image class="home-card__dlapp-icon" :src="downloadGlyph" mode="aspectFit" />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<text class="home-card__spct" :class="{ 'home-card__spct--over': storageOver }">{{ storagePercentText
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="home-card__bar">
|
||||
<view class="home-card__bar-fill" :class="{ 'home-card__bar-fill--over': storageOver }"
|
||||
@@ -1741,7 +1777,7 @@ defineExpose({
|
||||
t("article.tagPending") }}</text>
|
||||
</view>
|
||||
<text class="article-card__desc">{{ articlesApi.plainText(row.Brief, 100) || t("article.noBrief")
|
||||
}}</text>
|
||||
}}</text>
|
||||
<view class="article-card__meta">
|
||||
<image v-if="row.AuthorAvatarUrl" class="article-card__avatar"
|
||||
:src="absoluteFileUrl(row.AuthorAvatarUrl)" mode="aspectFill" />
|
||||
@@ -1786,7 +1822,7 @@ defineExpose({
|
||||
<u-switch v-if="data.IsManager" :model-value="tree.PublicIndc === 'Y'" size="40"
|
||||
:active-color="primary" @change="onPublicToggle" />
|
||||
<text v-if="data.IsManager" class="ft-badge ft-badge--admin">{{ t("FamilyTreePage.managerTag")
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1893,7 +1929,7 @@ defineExpose({
|
||||
<!-- 当前族员:从概览移入,夫妻/子女列表都是相对此人 -->
|
||||
<view v-if="loaded && currentPerson" class="ft-card">
|
||||
<view class="ft-card__head"><text class="ft-card__title">{{ t("FamilyTreePage.currentPerson")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view class="person-hero">
|
||||
<view class="person-hero__avatar"
|
||||
:style="avatarFallbackStyle(!!currentPerson?.AvatarUrl, currentPerson?.Gender)">
|
||||
@@ -1908,7 +1944,7 @@ defineExpose({
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text v-if="currentPerson?.PersonId" class="person-hero__chip">{{ personChipText(currentPerson)
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1951,12 +1987,12 @@ defineExpose({
|
||||
<!-- 新增入口与行尾操作同一把闸:当前锚点不可编(未绑定/出支系)时隐藏 -->
|
||||
<view class="ft-card__head">
|
||||
<view class="ft-card__title-group"><text class="ft-card__title">{{ t("FamilyTreePage.spouseTitle")
|
||||
}}</text><text class="ft-card__count">{{ spouseMaps.length }}</text></view>
|
||||
}}</text><text class="ft-card__count">{{ spouseMaps.length }}</text></view>
|
||||
<view v-if="data.IsCanAmend" class="ft-card__add" @tap="openQuickCreate('spouse')"><u-icon
|
||||
name="plus" size="26" :color="primary" /><text>{{ t("FamilyTreePage.addSpouse") }}</text></view>
|
||||
</view>
|
||||
<view v-if="!visibleSpouses.length" class="ft-empty"><text>{{ t("FamilyTreePage.spouseEmpty")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view v-for="record in visibleSpouses" :key="record.SpouseId" class="ft-mrow">
|
||||
<view class="ft-av"
|
||||
:style="avatarFallbackStyle(!!personAvatar(record.SpouseId), personGender(record.SpouseId, record.Gender))">
|
||||
@@ -1992,13 +2028,13 @@ defineExpose({
|
||||
<view class="ft-card">
|
||||
<view class="ft-card__head">
|
||||
<view class="ft-card__title-group"><text class="ft-card__title">{{ t("FamilyTreePage.childTitle")
|
||||
}}</text><text class="ft-card__count">{{ childMaps.length }}</text></view>
|
||||
}}</text><text class="ft-card__count">{{ childMaps.length }}</text></view>
|
||||
<view v-if="data.IsCanAmend" class="ft-card__add" @tap="openQuickCreate('child')"><u-icon
|
||||
name="plus" size="26" :color="primary" /><text>{{ t("FamilyTreePage.addChildBtn") }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!visibleChildren.length" class="ft-empty"><text>{{ t("FamilyTreePage.childEmpty")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view v-for="record in visibleChildren" :key="record.ChildrenId" class="ft-mrow">
|
||||
<view class="ft-av"
|
||||
:style="avatarFallbackStyle(!!personAvatar(record.ChildrenId), personGender(record.ChildrenId, record.Gender))">
|
||||
@@ -2038,7 +2074,7 @@ defineExpose({
|
||||
<view v-if="data.IsManager && pendingPermissions.length" class="ft-card">
|
||||
<view class="ft-card__head">
|
||||
<view class="ft-card__title-group"><text class="ft-card__title">{{ t("FamilyTreePage.permPending")
|
||||
}}</text><text class="ft-card__count">{{ pendingPermissions.length }}</text></view>
|
||||
}}</text><text class="ft-card__count">{{ pendingPermissions.length }}</text></view>
|
||||
</view>
|
||||
<view v-for="record in pendingPermissions" :key="record.UserName" class="ft-perm-row">
|
||||
<view class="ft-perm-row__main"><text class="ft-perm-row__name">{{ record.UserLocalName ||
|
||||
@@ -2062,10 +2098,10 @@ defineExpose({
|
||||
<view v-if="data.IsManager" class="ft-card">
|
||||
<view class="ft-card__head">
|
||||
<view class="ft-card__title-group"><text class="ft-card__title">{{ t("FamilyTreePage.permManager")
|
||||
}}</text><text class="ft-card__count">{{ managerPermissions.length }}</text></view>
|
||||
}}</text><text class="ft-card__count">{{ managerPermissions.length }}</text></view>
|
||||
</view>
|
||||
<view v-if="!managerPermissions.length" class="ft-empty"><text>{{ t("FamilyTreePage.permEmpty")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view v-for="record in managerPermissions" :key="record.UserName" class="ft-perm-row">
|
||||
<view class="ft-perm-row__main"><text class="ft-perm-row__name">{{ record.UserLocalName ||
|
||||
record.UserName
|
||||
@@ -2300,7 +2336,7 @@ defineExpose({
|
||||
<view class="person-hero__line">
|
||||
<text class="rel-name">{{ record.SpouseSurname }}{{ record.SpouseGenealogyName }}</text>
|
||||
<text class="person-hero__gender">{{ genderText(personGender(record.SpouseId, record.Gender))
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text class="person-hero__chip">
|
||||
@@ -2337,7 +2373,7 @@ defineExpose({
|
||||
<text class="sub-label">{{ t("FamilyTreePage.marryDate") }}</text>
|
||||
<view class="sub-picker">
|
||||
<text class="sub-picker-text">{{ datePart(record.MarryDate) || t("AdminPage.notSetTip")
|
||||
}}</text>
|
||||
}}</text>
|
||||
<u-icon name="arrow-right" size="24" color="#c4c8cf" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -2353,7 +2389,7 @@ defineExpose({
|
||||
<view class="sub-picker">
|
||||
<text class="sub-picker-text">{{
|
||||
datePart(record.DivorceDate) || t("AdminPage.notSetTip")
|
||||
}}</text>
|
||||
}}</text>
|
||||
<u-icon name="arrow-right" size="24" color="#c4c8cf" />
|
||||
</view>
|
||||
</view>
|
||||
@@ -2439,7 +2475,7 @@ defineExpose({
|
||||
<view class="person-hero__line">
|
||||
<text class="rel-name">{{ record.ChildrenSurname }}{{ record.ChildrenGenealogyName }}</text>
|
||||
<text class="person-hero__gender">{{ genderText(personGender(record.ChildrenId, record.Gender))
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text class="person-hero__chip">
|
||||
@@ -2550,7 +2586,7 @@ defineExpose({
|
||||
<text class="rel-name">{{ record.UserLocalName || record.UserName }}</text>
|
||||
<text class="rel-sub">{{
|
||||
record.ManagerIndc === "Y" ? t("FamilyTreePage.managerTag") : t("FamilyTreePage.memberTag")
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="perm-ops">
|
||||
<view class="perm-op perm-op--danger" @tap="rejectPermission(record)">
|
||||
@@ -2727,7 +2763,7 @@ defineExpose({
|
||||
<!-- 服务器文件列表限高滚动:文件多了不挤掉密码框/警告/按钮 -->
|
||||
<scroll-view v-if="!localFileName" scroll-y class="ft-exchange__list">
|
||||
<view v-if="importFilesLoading" class="ft-empty"><text>{{ t("FamilyTreePage.exchangeFileLoading")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view v-else-if="!importFiles.length" class="ft-empty"><text>{{ t(imScope === "SUB" ?
|
||||
"FamilyTreePage.exchangeFileEmptySub" : "FamilyTreePage.exchangeFileEmpty") }}</text></view>
|
||||
<view v-for="file in importFiles" :key="file.FileName" class="ft-exchange__row"
|
||||
@@ -2748,7 +2784,7 @@ defineExpose({
|
||||
<view v-if="backupLoading" class="ft-empty"><text>{{ t("FamilyTreePage.exchangeFileLoading") }}</text>
|
||||
</view>
|
||||
<view v-else-if="!backupFiles.length" class="ft-empty"><text>{{ t("FamilyTreePage.exchangeBackupEmpty")
|
||||
}}</text></view>
|
||||
}}</text></view>
|
||||
<view v-for="bk in backupFiles" :key="bk.FileName" class="ft-exchange__row"
|
||||
:class="{ 'ft-exchange__row--on': pickedBackup === bk.FileName }" @tap="pickedBackup = bk.FileName">
|
||||
<view class="ft-exchange__row-main">
|
||||
@@ -2814,7 +2850,7 @@ defineExpose({
|
||||
<view class="ft-sheet__foot">
|
||||
<view class="ft-sheet__btn" @tap="cancelTreeEdit"><text>{{ t("AdminPage.cancelBut") }}</text></view>
|
||||
<view class="ft-sheet__btn ft-sheet__btn--primary" @tap="saveTreeEdit"><text>{{ t("AdminPage.saveBut")
|
||||
}}</text>
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -2932,6 +2968,22 @@ defineExpose({
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 仅 H5 下载 App 图标:放在「网盘存储空间」标题旁,绿描边 + 柔光圆底(与 sicon 同色系,白卡可见) */
|
||||
.home-card__dlapp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 50%;
|
||||
background: var(--fg-soft, #e6f6ec);
|
||||
}
|
||||
|
||||
.home-card__dlapp-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
|
||||
.home-card__avatar {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
"typeVip": "VIP",
|
||||
"typeSvip": "SVIP",
|
||||
"avatarUploadedTip": "Avatar updated",
|
||||
"avatarUploadFailed": "Avatar upload failed"
|
||||
"avatarUploadFailed": "Avatar upload failed",
|
||||
"downloadApp": "Download App",
|
||||
"downloadingApp": "Downloading…",
|
||||
"downloadStarted": "Downloading youjiala.apk…"
|
||||
},
|
||||
"article": {
|
||||
"title": "Family Culture",
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
"typeVip": "VIP",
|
||||
"typeSvip": "SVIP",
|
||||
"avatarUploadedTip": "头像已更新",
|
||||
"avatarUploadFailed": "头像上传失败"
|
||||
"avatarUploadFailed": "头像上传失败",
|
||||
"downloadApp": "下载 App",
|
||||
"downloadingApp": "正在下载…",
|
||||
"downloadStarted": "开始下载 youjiala.apk…"
|
||||
},
|
||||
"article": {
|
||||
"title": "有家文化传承",
|
||||
|
||||
Reference in new issue
Block a user