add About
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 timi
|
Copyright (c) 2026 imyeyu.com
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="about-page">
|
||||||
|
<section class="brand" v-entrance-transition>
|
||||||
|
<logo />
|
||||||
|
<h1 v-text="appName" />
|
||||||
|
<p v-text="appDescription" />
|
||||||
|
</section>
|
||||||
|
<t-cell-group title="协议" theme="card" v-entrance-transition="70">
|
||||||
|
<t-cell
|
||||||
|
v-for="item in agreementItemList"
|
||||||
|
:key="item.code"
|
||||||
|
:title="item.title"
|
||||||
|
arrow
|
||||||
|
hover
|
||||||
|
@click="openAgreement(item)"
|
||||||
|
>
|
||||||
|
<template #leftIcon>
|
||||||
|
<t-icon :name="item.icon" size="1.75rem" />
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
|
</t-cell-group>
|
||||||
|
<footer class="footer" v-entrance-transition="140">
|
||||||
|
<p>技术支持:夜雨</p>
|
||||||
|
<p>Copyright © 2026 imyeyu.com</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { type Setting, SettingAPI } from "timi-web-api";
|
||||||
|
import Logo from "@/pages/user/component/Logo.vue";
|
||||||
|
import { getErrorMessage } from "@/utils/error";
|
||||||
|
import { Message } from "@/utils/message";
|
||||||
|
|
||||||
|
type AgreementCode = "SERVICE_LICENSE" | "PRIVACY_LICENSE" | "OPEN_SOURCE_LICENSE";
|
||||||
|
type AgreementRouteName = "ServiceAgreement" | "PrivacyAgreement" | "OpenSourceAgreement";
|
||||||
|
type AgreementItem = {
|
||||||
|
code: AgreementCode;
|
||||||
|
icon: string;
|
||||||
|
routeName: AgreementRouteName;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "About"
|
||||||
|
});
|
||||||
|
|
||||||
|
const appName = "糕店客户管理";
|
||||||
|
const appDescription = "面向门店的客户、登记、积分与经营管理工具";
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const agreementItemList: AgreementItem[] = [
|
||||||
|
{
|
||||||
|
code: "SERVICE_LICENSE",
|
||||||
|
icon: "file-attachment",
|
||||||
|
routeName: "ServiceAgreement",
|
||||||
|
title: "服务协议"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "PRIVACY_LICENSE",
|
||||||
|
icon: "secured",
|
||||||
|
routeName: "PrivacyAgreement",
|
||||||
|
title: "隐私协议"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "OPEN_SOURCE_LICENSE",
|
||||||
|
icon: "code",
|
||||||
|
routeName: "OpenSourceAgreement",
|
||||||
|
title: "开源软件协议"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const settingMap = ref<Record<string, Setting>>({});
|
||||||
|
|
||||||
|
function getAgreementId(code: AgreementCode): string {
|
||||||
|
return settingMap.value[code]?.value?.trim() || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openAgreement(item: AgreementItem): Promise<void> {
|
||||||
|
const articleId = getAgreementId(item.code);
|
||||||
|
if (!articleId) {
|
||||||
|
Message.warning(`${item.title}暂未配置`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await router.push({
|
||||||
|
name: item.routeName,
|
||||||
|
params: {
|
||||||
|
id: articleId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSettings(): Promise<void> {
|
||||||
|
try {
|
||||||
|
settingMap.value = await SettingAPI.map("GAO_SYSTEM");
|
||||||
|
} catch (error) {
|
||||||
|
Message.error(getErrorMessage(error, "协议配置加载失败"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadSettings();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.about-page {
|
||||||
|
gap: 1rem;
|
||||||
|
display: flex;
|
||||||
|
padding: calc(var(--app-nav-height) + 1rem) 0 5rem;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
padding: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: .875rem 0 .5rem;
|
||||||
|
color: #0f172a;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: #52607a;
|
||||||
|
font-size: .875rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 1.25rem 1rem calc(1rem + env(safe-area-inset-bottom, 0));
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
color: #52607a;
|
||||||
|
font-size: .8125rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.theme-dark) {
|
||||||
|
.about-page {
|
||||||
|
.brand {
|
||||||
|
h1 {
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer p {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<div class="agreement-page">
|
||||||
|
<template v-if="article">
|
||||||
|
<header class="header" v-entrance-transition>
|
||||||
|
<h3 v-text="article.title || '协议'" />
|
||||||
|
<markdown-view
|
||||||
|
v-if="article.description"
|
||||||
|
class="description"
|
||||||
|
:content="article.description"
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
|
<article-view
|
||||||
|
:article="article"
|
||||||
|
empty-text="暂无协议正文"
|
||||||
|
:resolve-attachment-url="resolveAttachmentUrl"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<t-empty
|
||||||
|
v-else
|
||||||
|
:description="isLoading ? '正在加载协议' : '协议不存在'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { type Article, ArticleAPI, AttachmentAPI } from "timi-web-api";
|
||||||
|
import { ArticleView } from "timi-tdesign-mobile";
|
||||||
|
import { MarkdownView } from "timi-web";
|
||||||
|
import { getErrorMessage } from "@/utils/error";
|
||||||
|
import { Message } from "@/utils/message";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "Agreement"
|
||||||
|
});
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const article = ref<Article>();
|
||||||
|
const isLoading = ref(false);
|
||||||
|
let loadToken = 0;
|
||||||
|
|
||||||
|
function resolveAttachmentUrl(attachmentId: string): string {
|
||||||
|
return AttachmentAPI.getReadURL(attachmentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadArticle(): Promise<void> {
|
||||||
|
const requestToken = loadToken + 1;
|
||||||
|
loadToken = requestToken;
|
||||||
|
article.value = undefined;
|
||||||
|
const articleId = String(route.params.id || "").trim();
|
||||||
|
if (!articleId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
const result = await ArticleAPI.detail(articleId);
|
||||||
|
if (requestToken !== loadToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
article.value = result;
|
||||||
|
} catch (error) {
|
||||||
|
Message.error(getErrorMessage(error, "协议加载失败"));
|
||||||
|
} finally {
|
||||||
|
if (requestToken === loadToken) {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => route.params.id, async () => {
|
||||||
|
await loadArticle();
|
||||||
|
}, { immediate: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.agreement-page {
|
||||||
|
padding: var(--app-nav-height) 0 1rem 0;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #0f172a;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #52607a;
|
||||||
|
font-size: .875rem;
|
||||||
|
margin-top: .5rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.content) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html.theme-dark) {
|
||||||
|
.agreement-page {
|
||||||
|
.header {
|
||||||
|
h1 {
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -87,7 +87,7 @@ type MenuItem = {
|
|||||||
|
|
||||||
type MenuGroup = {
|
type MenuGroup = {
|
||||||
items: MenuItem[];
|
items: MenuItem[];
|
||||||
title: string;
|
title?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -234,6 +234,16 @@ const menuGroupList = computed<MenuGroup[]>(() => [
|
|||||||
path: "/management/qr-code",
|
path: "/management/qr-code",
|
||||||
title: "生成客户二维码",
|
title: "生成客户二维码",
|
||||||
visible: userStore.hasPermissions(permissionCodes.qrCode.create)
|
visible: userStore.hasPermissions(permissionCodes.qrCode.create)
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
icon: "info-circle",
|
||||||
|
path: "/management/about",
|
||||||
|
title: "关于",
|
||||||
|
visible: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { RouteRecordRaw } from "vue-router";
|
import type { RouteRecordRaw } from "vue-router";
|
||||||
|
import About from "@/pages/setting/About.vue";
|
||||||
|
import Agreement from "@/pages/setting/Agreement.vue";
|
||||||
import AppSettings from "@/pages/setting/AppSettings.vue";
|
import AppSettings from "@/pages/setting/AppSettings.vue";
|
||||||
import NotifyList from "@/pages/notify/NotifyList.vue";
|
import NotifyList from "@/pages/notify/NotifyList.vue";
|
||||||
import NotifyCreate from "@/pages/notify/NotifyCreate.vue";
|
import NotifyCreate from "@/pages/notify/NotifyCreate.vue";
|
||||||
@@ -146,6 +148,62 @@ export const storeRoutes: RouteRecordRaw[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const managementSettingRoutes: RouteRecordRaw[] = [
|
export const managementSettingRoutes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: "/management/about",
|
||||||
|
name: "About",
|
||||||
|
component: About,
|
||||||
|
meta: {
|
||||||
|
depth: 3,
|
||||||
|
navBarVisible: true,
|
||||||
|
navBarCanBack: true,
|
||||||
|
navBarTitle: "关于",
|
||||||
|
tabBarVisible: false,
|
||||||
|
bodyBackground: "#F5F5F8",
|
||||||
|
darkBodyBackground: "#10161f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/about/service-agreement/:id",
|
||||||
|
name: "ServiceAgreement",
|
||||||
|
component: Agreement,
|
||||||
|
meta: {
|
||||||
|
depth: 4,
|
||||||
|
navBarVisible: true,
|
||||||
|
navBarCanBack: true,
|
||||||
|
navBarTitle: "服务协议",
|
||||||
|
tabBarVisible: false,
|
||||||
|
bodyBackground: "#FFF",
|
||||||
|
darkBodyBackground: "#10161f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/about/privacy-agreement/:id",
|
||||||
|
name: "PrivacyAgreement",
|
||||||
|
component: Agreement,
|
||||||
|
meta: {
|
||||||
|
depth: 4,
|
||||||
|
navBarVisible: true,
|
||||||
|
navBarCanBack: true,
|
||||||
|
navBarTitle: "隐私协议",
|
||||||
|
tabBarVisible: false,
|
||||||
|
bodyBackground: "#FFF",
|
||||||
|
darkBodyBackground: "#10161f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/about/open-source-agreement/:id",
|
||||||
|
name: "OpenSourceAgreement",
|
||||||
|
component: Agreement,
|
||||||
|
meta: {
|
||||||
|
depth: 4,
|
||||||
|
navBarVisible: true,
|
||||||
|
navBarCanBack: true,
|
||||||
|
navBarTitle: "开源软件协议",
|
||||||
|
tabBarVisible: false,
|
||||||
|
bodyBackground: "#F5F5F8",
|
||||||
|
darkBodyBackground: "#10161f"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/management/settings",
|
path: "/management/settings",
|
||||||
name: "AppSettings",
|
name: "AppSettings",
|
||||||
|
|||||||
Reference in New Issue
Block a user