From 2a4545bc0023528fc642f9109d1e7a837d5f40c7 Mon Sep 17 00:00:00 2001 From: MaDaLei Date: Sun, 19 Apr 2026 14:26:25 +0800 Subject: [PATCH] deploy: update logo and latest build --- README.en.md | 2 +- README.md | 9 +- index.html | 4 +- login.html | 8 +- register-boss.html | 4 +- register-staff.html | 2 +- report.html | 2 +- src/api/index.js | 4 + src/assets/global.css | 2 +- src/components/report/ReportShareModal.vue | 17 ++-- src/manifest.json | 4 +- src/pages.json | 2 +- .../appointment/CustAppointmentCreate.vue | 82 ++++++++++++++++++- src/pages/home/Home.vue | 54 +++++++++--- src/pages/login/Login.vue | 4 +- src/pages/mine/Mine.vue | 20 +++-- src/pages/mine/Profile.vue | 2 +- src/pages/mine/Store.vue | 2 +- src/pages/report-view/reportView.vue | 32 ++++++-- src/pages/report/Report.vue | 21 +++++ src/utils/brand.js | 4 + src/utils/reportOpenTrack.js | 39 +++++++++ src/utils/reportPosterDraw.js | 2 +- src/utils/reportShare.js | 2 +- src/views/ReportView.vue | 25 +++++- 25 files changed, 293 insertions(+), 56 deletions(-) create mode 100644 src/utils/brand.js create mode 100644 src/utils/reportOpenTrack.js diff --git a/README.en.md b/README.en.md index d2750b9..caa3cd9 100644 --- a/README.en.md +++ b/README.en.md @@ -1,7 +1,7 @@ # petstore-frontend #### Description -宠伴生活馆 +宠小它 #### Software Architecture Software architecture description diff --git a/README.md b/README.md index 1f60fed..508d922 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# 宠伴生活馆 - UniApp 项目 +# 宠小它 - UniApp 项目 + +> 品牌:宠小它 · 用心宠小它,温暖伴一生 · 智慧宠物门店服务系统 从 H5 (Vite+Vue3+Vant) 迁移到 UniApp+Vue3,用于生成微信小程序。 @@ -128,3 +130,8 @@ npm run dev:h5 ### 报告分享链接与二维码(小程序) 「生成报告」弹层里的链接与二维码指向 **H5** `report.html?token=`,需与线上部署的静态站点一致。请在对应环境的 `.env` / `.env.production` 中配置 **`VITE_REPORT_PUBLIC_ORIGIN`**(例如 `https://www.example.com`,无尾斜杠)。未配置时仍可复制话术,但链接为空、二维码不展示,并会在弹层内提示。 + +### 宠主预约草稿(P0 C3) + +当前实现:**已登录**用户在 `CustAppointmentCreate` 填写的内容会 debounce 写入本地 `uni.storage`(7 天有效),离开页/重进可恢复;提交成功会清除草稿。 +产品文档中的 **「未登录可先填单、提交时再登录并恢复草稿」** 需同时将「新建预约」页加入公开路由(如 `App.vue` 的 `isPublicRoute`)并在登录回跳后合并草稿;若未做公开路由,未登录用户仍会在进入预约页前被拦截到登录。 diff --git a/index.html b/index.html index 81fc441..8c96816 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,8 @@ - 宠伴生活馆 - + 宠小它 +
diff --git a/login.html b/login.html index e6f31e7..c3fef0d 100644 --- a/login.html +++ b/login.html @@ -3,7 +3,7 @@ - 登录 - 宠伴生活馆 + 登录 - 宠小它 diff --git a/src/pages/report/Report.vue b/src/pages/report/Report.vue index 380c562..34569d3 100644 --- a/src/pages/report/Report.vue +++ b/src/pages/report/Report.vue @@ -167,6 +167,9 @@ :class="{ 'submit-fixed--scrolled': hasScrolled }" :style="submitFixedStyle" > + + 提交后不可修改,请确认照片与备注无误。 + @@ -183,6 +186,8 @@ :show="shareModalOpen" :report-token="shareToken" :pet-name="sharePetName" + :store-name="shareStoreName" + :service-type="shareServiceType" @close="onShareModalClose" @preview="onSharePreview" /> @@ -236,6 +241,8 @@ const submitting = ref(false) const shareModalOpen = ref(false) const shareToken = ref('') const sharePetName = ref('') +const shareStoreName = ref('') +const shareServiceType = ref('') const basicInfoCollapsed = ref(false) const hasScrolled = ref(false) const keyboardHeight = ref(0) @@ -701,6 +708,8 @@ const submitReport = async () => { const token = res.data.reportToken shareToken.value = token sharePetName.value = report.value.petName || '' + shareStoreName.value = storeInfo?.name || '' + shareServiceType.value = report.value.serviceType || '' report.value = { petName: '', serviceType: '', appointmentTime: '', beforeMedia: [], afterMedia: [], duringMedia: [], remark: '' } currentAppointmentId.value = null basicInfoCollapsed.value = false @@ -715,6 +724,8 @@ const onShareModalClose = () => { shareModalOpen.value = false shareToken.value = '' sharePetName.value = '' + shareStoreName.value = '' + shareServiceType.value = '' } const onSharePreview = () => { @@ -722,6 +733,8 @@ const onSharePreview = () => { shareModalOpen.value = false shareToken.value = '' sharePetName.value = '' + shareStoreName.value = '' + shareServiceType.value = '' if (t) { uni.navigateTo({ url: `/pages/report-view/reportView?token=${encodeURIComponent(t)}` }) } @@ -1014,6 +1027,14 @@ const onRemarkBlur = () => { box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.08); background: rgba(250, 250, 248, 0.985); } +.report-lock-hint { + font-size: 12px; + color: #8a8a84; + line-height: 1.45; + text-align: center; + margin-bottom: 10px; + padding: 0 8px; +} .submit-btn--fixed { box-shadow: 0 5px 16px rgba(0, 0, 0, 0.1); } diff --git a/src/utils/brand.js b/src/utils/brand.js new file mode 100644 index 0000000..60d28a0 --- /dev/null +++ b/src/utils/brand.js @@ -0,0 +1,4 @@ +/** 品牌与 Slogan(单一来源,供页面与分享兜底引用) */ +export const BRAND_NAME = '宠小它' +export const BRAND_SLOGAN_MAIN = '用心宠小它,温暖伴一生' +export const BRAND_SLOGAN_SUB = '智慧宠物门店服务系统' diff --git a/src/utils/reportOpenTrack.js b/src/utils/reportOpenTrack.js new file mode 100644 index 0000000..d28bc59 --- /dev/null +++ b/src/utils/reportOpenTrack.js @@ -0,0 +1,39 @@ +import { postReportOpenTrack } from '../api/index.js' + +const STORAGE_PREFIX = 'petstore_report_seen_' + +function storageKeyForToken(token) { + let h = 0 + const s = String(token || '') + for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0 + return STORAGE_PREFIX + Math.abs(h).toString(36) +} + +/** + * P0 埋点:报告打开(首次 / 再次)。失败静默,不影响阅读。 + * @param {string} token report_token + */ +export function trackReportOpen(token) { + if (!token) return + const key = storageKeyForToken(token) + let visitType = 'first' + try { + const prev = uni.getStorageSync(key) + if (prev) visitType = 'repeat' + else uni.setStorageSync(key, '1') + } catch (_) { + visitType = 'repeat' + } + postReportOpenTrack(token, visitType).catch(() => {}) +} + +const REPORT_FETCH_MS = 10000 + +export function getReportByTokenWithTimeout(getReportByToken, token) { + return Promise.race([ + getReportByToken(token), + new Promise((_, reject) => { + setTimeout(() => reject(new Error('TIMEOUT')), REPORT_FETCH_MS) + }) + ]) +} diff --git a/src/utils/reportPosterDraw.js b/src/utils/reportPosterDraw.js index 8594c10..b39d8a3 100644 --- a/src/utils/reportPosterDraw.js +++ b/src/utils/reportPosterDraw.js @@ -95,7 +95,7 @@ function drawBgGradient(ctx, height) { export function drawReportPoster(ctx, data) { const { storeName, petName, beforeImg, afterImg, qrImg, testimonial } = data - const name = storeName || '宠伴生活馆' + const name = storeName || '宠小它' const PAD = 28 const pet = petName || '宝贝' diff --git a/src/utils/reportShare.js b/src/utils/reportShare.js index 6b7fb6d..4ecae6f 100644 --- a/src/utils/reportShare.js +++ b/src/utils/reportShare.js @@ -5,7 +5,7 @@ import { imgUrl } from '../api/index.js' */ export function buildReportShareTitle(report) { if (!report) return '洗护前后对比' - const store = report.store?.name || '宠伴生活馆' + const store = report.store?.name || '宠小它' const pet = report.petName || '爱宠' const svc = (report.serviceType || '').trim() const svcPart = svc ? `·${svc}` : '' diff --git a/src/views/ReportView.vue b/src/views/ReportView.vue index 05b287d..8b62197 100644 --- a/src/views/ReportView.vue +++ b/src/views/ReportView.vue @@ -28,8 +28,8 @@ mode="aspectFit" />
- -
宠物服务,让爱更专业
+ +
用心宠小它,温暖伴一生
@@ -38,6 +38,10 @@
+
+ 本页含宠物服务影像,请勿公开转发或发群 +
+
服务报告
@@ -134,6 +138,7 @@ import { ref, computed, onMounted } from 'vue' import { onLoad } from '@dcloudio/uni-app' import { getReportByToken, imgUrl, submitReportTestimonial } from '../api/index.js' +import { trackReportOpen, getReportByTokenWithTimeout } from '../utils/reportOpenTrack.js' import { drawReportPoster, POSTER_W, computePosterLogicalHeight } from '../utils/reportPosterDraw.js' import { formatDateTimeYMDHM } from '../utils/datetime.js' import AppIcon from '../components/AppIcon.vue' @@ -235,9 +240,10 @@ const loadReport = async () => { loading.value = true try { - const res = await getReportByToken(token) + const res = await getReportByTokenWithTimeout(getReportByToken, token) if (res && res.code === 200 && res.data) { reportData.value = res.data + trackReportOpen(token) } else if (res && res.code === 404) { reportData.value = null notFound.value = true @@ -247,7 +253,8 @@ const loadReport = async () => { } } catch (e) { reportData.value = null - loadError.value = NETWORK_ERROR_MSG + loadError.value = + e && e.message === 'TIMEOUT' ? '加载超时,请检查网络后重试' : NETWORK_ERROR_MSG } finally { loading.value = false } @@ -469,4 +476,14 @@ onMounted(() => loadReport()) .section-label { font-size: 15px; font-weight: 700; color: #1f2937; margin-bottom: 10px; } .remark-content { background: #f8fafc; border: 1px solid #e8edf4; border-radius: 12px; padding: 14px; font-size: 14px; color: #64748b; line-height: 1.6; min-height: 60px; } .action-section { margin: 0 16px 24px; } +.report-privacy-bar { + margin: 0 16px 12px; + padding: 10px 12px; + font-size: 12px; + color: #92400e; + line-height: 1.45; + background: #fffbeb; + border: 1px solid #fde68a; + border-radius: 10px; +}