From e06f0566b44644bf057d3fba970c9958ee2341cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Tue, 29 Sep 2026 10:57:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E3=80=81UI=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 12 + scripts/selfcheck-naming.mjs | 71 ++ src/App.vue | 189 +++- src/api/coupon.ts | 91 ++ src/api/event.ts | 171 +++ src/api/member.ts | 103 +- src/api/note.ts | 128 +++ src/api/quota.ts | 43 +- src/api/request.ts | 83 +- src/api/upload.ts | 47 + src/components/Confetti.vue | 4 +- src/components/Sticker.vue | 6 + src/components/TabBar.vue | 6 +- src/components/card/CardTile.vue | 757 +++++++++++++ src/components/coupon/CouponCard.vue | 274 +++++ src/components/event/SeatMap.vue | 1004 +++++++++++++++++ src/components/home/PaneLibrary.vue | 316 ++++-- src/components/home/PaneMine.vue | 405 ++++--- src/components/home/PaneRefresher.vue | 25 + src/components/home/PaneWorkbench.vue | 399 ++++--- src/components/member/PromoCodeInput.vue | 136 +++ src/components/mine/MineDrawers.vue | 948 ++++++++++++++++ src/components/tool/ToolIdle.vue | 69 ++ src/components/tool/ToolPage.vue | 123 ++ src/components/tool/ToolRunning.vue | 94 ++ src/components/tool/ToolSliderRow.vue | 92 ++ src/components/vip/QuotaBar.vue | 4 +- src/components/vip/QuotaGate.vue | 4 +- src/components/vip/VipCard.vue | 4 +- src/components/vip/VipFloatAd.vue | 4 +- src/composables/useImageTool.ts | 142 +++ src/config/card-styles.ts | 279 +++++ src/config/card-templates.ts | 118 ++ src/config/features.ts | 80 ++ src/manifest.json | 3 + src/pages.json | 63 +- src/pages/index/index.vue | 158 +-- src/pages/mine/profile.vue | 82 +- src/pages/tools/image/annotate.vue | 8 + src/pages/tools/image/avatarfx.vue | 27 +- src/pages/tools/image/collage.vue | 14 +- src/pages/tools/image/matting.vue | 551 ++++++--- src/pages/tools/image/qrcode.vue | 627 ++++++++-- src/pages/tools/image/watermark.vue | 44 +- src/pages/workbench/edit.vue | 4 +- src/pkg-event/list.vue | 245 ++++ src/pkg-event/query.vue | 612 ++++++++++ src/pkg-member/coupon/index.vue | 279 +++++ src/pkg-member/member/detail.vue | 891 +++++++++++++++ src/pkg-member/member/index.vue | 130 ++- src/pkg-member/member/orders.vue | 42 +- src/pkg-member/quota/index.vue | 37 +- src/pkg-note/edit.vue | 580 ++++++++++ src/pkg-note/list.vue | 631 +++++++++++ src/pkg-style/icons.ts | 152 +++ src/pkg-style/sections/SecOne.vue | 825 ++++++++++++++ src/pkg-style/sections/SecThree.vue | 508 +++++++++ src/pkg-style/sections/SecTwo.vue | 664 +++++++++++ src/pkg-style/showcase.vue | 134 +++ src/pkg-style/static/icons/anchor.png | Bin 0 -> 25985 bytes src/pkg-style/static/icons/atom.png | Bin 0 -> 35908 bytes src/pkg-style/static/icons/avatar-woman.png | Bin 0 -> 23456 bytes src/pkg-style/static/icons/badge-bolt.png | Bin 0 -> 23547 bytes src/pkg-style/static/icons/badge-crown.png | Bin 0 -> 34908 bytes src/pkg-style/static/icons/badge-heart.png | Bin 0 -> 29711 bytes src/pkg-style/static/icons/badge-star.png | Bin 0 -> 25499 bytes src/pkg-style/static/icons/balloon.png | Bin 0 -> 22572 bytes src/pkg-style/static/icons/bell.png | Bin 0 -> 26651 bytes src/pkg-style/static/icons/bookA.png | Bin 0 -> 31554 bytes src/pkg-style/static/icons/brain.png | Bin 0 -> 29426 bytes src/pkg-style/static/icons/briefcase.png | Bin 0 -> 24370 bytes src/pkg-style/static/icons/broballoon.png | Bin 0 -> 13338 bytes src/pkg-style/static/icons/burger.png | Bin 0 -> 36391 bytes src/pkg-style/static/icons/cake.png | Bin 0 -> 29064 bytes src/pkg-style/static/icons/camera.png | Bin 0 -> 33264 bytes src/pkg-style/static/icons/cameraretro.png | Bin 0 -> 34971 bytes src/pkg-style/static/icons/cart.png | Bin 0 -> 26135 bytes src/pkg-style/static/icons/chart.png | Bin 0 -> 23369 bytes src/pkg-style/static/icons/chat.png | Bin 0 -> 25205 bytes src/pkg-style/static/icons/chatdots.png | Bin 0 -> 23711 bytes src/pkg-style/static/icons/clipboard.png | Bin 0 -> 24798 bytes src/pkg-style/static/icons/clock.png | Bin 0 -> 28033 bytes src/pkg-style/static/icons/cloud-down.png | Bin 0 -> 18401 bytes src/pkg-style/static/icons/cloud-video.png | Bin 0 -> 21844 bytes src/pkg-style/static/icons/coffee.png | Bin 0 -> 23155 bytes src/pkg-style/static/icons/college.png | Bin 0 -> 29546 bytes src/pkg-style/static/icons/community.png | Bin 0 -> 24534 bytes src/pkg-style/static/icons/compass.png | Bin 0 -> 38237 bytes src/pkg-style/static/icons/dinner.png | Bin 0 -> 31086 bytes src/pkg-style/static/icons/docscheck.png | Bin 0 -> 27716 bytes src/pkg-style/static/icons/donut.png | Bin 0 -> 35104 bytes src/pkg-style/static/icons/exampaper.png | Bin 0 -> 25464 bytes src/pkg-style/static/icons/film.png | Bin 0 -> 27230 bytes src/pkg-style/static/icons/folder.png | Bin 0 -> 19658 bytes src/pkg-style/static/icons/gamepad.png | Bin 0 -> 23723 bytes src/pkg-style/static/icons/gift.png | Bin 0 -> 30216 bytes src/pkg-style/static/icons/gradcap.png | Bin 0 -> 18432 bytes src/pkg-style/static/icons/hearts.png | Bin 0 -> 24371 bytes src/pkg-style/static/icons/hero-bot.png | Bin 0 -> 26458 bytes src/pkg-style/static/icons/icepop.png | Bin 0 -> 16952 bytes src/pkg-style/static/icons/live.png | Bin 0 -> 36213 bytes src/pkg-style/static/icons/lovepop.png | Bin 0 -> 14641 bytes src/pkg-style/static/icons/majorbag.png | Bin 0 -> 35992 bytes src/pkg-style/static/icons/mask.png | Bin 0 -> 27875 bytes src/pkg-style/static/icons/message.png | Bin 0 -> 17438 bytes src/pkg-style/static/icons/mic.png | Bin 0 -> 25780 bytes src/pkg-style/static/icons/miniapp.png | Bin 0 -> 31804 bytes src/pkg-style/static/icons/notebook.png | Bin 0 -> 24085 bytes src/pkg-style/static/icons/notes.png | Bin 0 -> 20424 bytes src/pkg-style/static/icons/orange-fruit.png | Bin 0 -> 106572 bytes src/pkg-style/static/icons/papers.png | Bin 0 -> 25117 bytes src/pkg-style/static/icons/pear.png | Bin 0 -> 19653 bytes src/pkg-style/static/icons/pencil.png | Bin 0 -> 18886 bytes src/pkg-style/static/icons/persona.png | Bin 0 -> 27291 bytes src/pkg-style/static/icons/plane.png | Bin 0 -> 64985 bytes src/pkg-style/static/icons/planet.png | Bin 0 -> 22374 bytes src/pkg-style/static/icons/resume.png | Bin 0 -> 22715 bytes src/pkg-style/static/icons/scan.png | Bin 0 -> 23961 bytes src/pkg-style/static/icons/script.png | Bin 0 -> 32973 bytes src/pkg-style/static/icons/selfbook.png | Bin 0 -> 24429 bytes src/pkg-style/static/icons/shield.png | Bin 0 -> 29397 bytes src/pkg-style/static/icons/shrimp.png | Bin 0 -> 25981 bytes src/pkg-style/static/icons/store.png | Bin 0 -> 34186 bytes src/pkg-style/static/icons/suitcase.png | Bin 0 -> 22088 bytes src/pkg-style/static/icons/vinyl.png | Bin 0 -> 36628 bytes src/pkg-style/static/icons/wework.png | Bin 0 -> 35052 bytes src/pkg-style/static/icons/wordbook.png | Bin 0 -> 33788 bytes src/pkg-style/style/showcase.scss | 249 ++++ src/stores/cardStyle.ts | 236 ++++ src/stores/user.ts | 25 +- src/utils/image/core.ts | 177 ++- src/utils/image/errors.ts | 78 ++ src/utils/image/history.ts | 136 +++ src/utils/image/matting.ts | 68 +- src/utils/image/name-collision.ts | 52 + src/utils/image/naming.ts | 86 ++ src/utils/image/task.ts | 52 +- src/utils/member-pay.ts | 34 +- src/utils/palette.ts | 16 + src/utils/pane-refresh.ts | 92 ++ src/utils/quota-pay.ts | 56 +- src/utils/z-index.ts | 35 + ....timestamp-1790161029749-4ba3e4a744878.mjs | 36 + ....timestamp-1790180057043-fe9dc0aae1d75.mjs | 36 + ....timestamp-1790180092082-e46dc62569487.mjs | 36 + ...s.timestamp-1790180142431-b740a0be265d.mjs | 36 + ....timestamp-1790180224337-1a90acfcfcbd5.mjs | 36 + ....timestamp-1790180269688-60bc6316745e5.mjs | 36 + ....timestamp-1790180300386-7432195a9a7d1.mjs | 36 + 149 files changed, 14066 insertions(+), 1120 deletions(-) create mode 100644 scripts/selfcheck-naming.mjs create mode 100644 src/api/coupon.ts create mode 100644 src/api/event.ts create mode 100644 src/api/note.ts create mode 100644 src/api/upload.ts create mode 100644 src/components/card/CardTile.vue create mode 100644 src/components/coupon/CouponCard.vue create mode 100644 src/components/event/SeatMap.vue create mode 100644 src/components/home/PaneRefresher.vue create mode 100644 src/components/member/PromoCodeInput.vue create mode 100644 src/components/mine/MineDrawers.vue create mode 100644 src/components/tool/ToolIdle.vue create mode 100644 src/components/tool/ToolPage.vue create mode 100644 src/components/tool/ToolRunning.vue create mode 100644 src/components/tool/ToolSliderRow.vue create mode 100644 src/composables/useImageTool.ts create mode 100644 src/config/card-styles.ts create mode 100644 src/config/card-templates.ts create mode 100644 src/config/features.ts create mode 100644 src/pkg-event/list.vue create mode 100644 src/pkg-event/query.vue create mode 100644 src/pkg-member/coupon/index.vue create mode 100644 src/pkg-member/member/detail.vue create mode 100644 src/pkg-note/edit.vue create mode 100644 src/pkg-note/list.vue create mode 100644 src/pkg-style/icons.ts create mode 100644 src/pkg-style/sections/SecOne.vue create mode 100644 src/pkg-style/sections/SecThree.vue create mode 100644 src/pkg-style/sections/SecTwo.vue create mode 100644 src/pkg-style/showcase.vue create mode 100644 src/pkg-style/static/icons/anchor.png create mode 100644 src/pkg-style/static/icons/atom.png create mode 100644 src/pkg-style/static/icons/avatar-woman.png create mode 100644 src/pkg-style/static/icons/badge-bolt.png create mode 100644 src/pkg-style/static/icons/badge-crown.png create mode 100644 src/pkg-style/static/icons/badge-heart.png create mode 100644 src/pkg-style/static/icons/badge-star.png create mode 100644 src/pkg-style/static/icons/balloon.png create mode 100644 src/pkg-style/static/icons/bell.png create mode 100644 src/pkg-style/static/icons/bookA.png create mode 100644 src/pkg-style/static/icons/brain.png create mode 100644 src/pkg-style/static/icons/briefcase.png create mode 100644 src/pkg-style/static/icons/broballoon.png create mode 100644 src/pkg-style/static/icons/burger.png create mode 100644 src/pkg-style/static/icons/cake.png create mode 100644 src/pkg-style/static/icons/camera.png create mode 100644 src/pkg-style/static/icons/cameraretro.png create mode 100644 src/pkg-style/static/icons/cart.png create mode 100644 src/pkg-style/static/icons/chart.png create mode 100644 src/pkg-style/static/icons/chat.png create mode 100644 src/pkg-style/static/icons/chatdots.png create mode 100644 src/pkg-style/static/icons/clipboard.png create mode 100644 src/pkg-style/static/icons/clock.png create mode 100644 src/pkg-style/static/icons/cloud-down.png create mode 100644 src/pkg-style/static/icons/cloud-video.png create mode 100644 src/pkg-style/static/icons/coffee.png create mode 100644 src/pkg-style/static/icons/college.png create mode 100644 src/pkg-style/static/icons/community.png create mode 100644 src/pkg-style/static/icons/compass.png create mode 100644 src/pkg-style/static/icons/dinner.png create mode 100644 src/pkg-style/static/icons/docscheck.png create mode 100644 src/pkg-style/static/icons/donut.png create mode 100644 src/pkg-style/static/icons/exampaper.png create mode 100644 src/pkg-style/static/icons/film.png create mode 100644 src/pkg-style/static/icons/folder.png create mode 100644 src/pkg-style/static/icons/gamepad.png create mode 100644 src/pkg-style/static/icons/gift.png create mode 100644 src/pkg-style/static/icons/gradcap.png create mode 100644 src/pkg-style/static/icons/hearts.png create mode 100644 src/pkg-style/static/icons/hero-bot.png create mode 100644 src/pkg-style/static/icons/icepop.png create mode 100644 src/pkg-style/static/icons/live.png create mode 100644 src/pkg-style/static/icons/lovepop.png create mode 100644 src/pkg-style/static/icons/majorbag.png create mode 100644 src/pkg-style/static/icons/mask.png create mode 100644 src/pkg-style/static/icons/message.png create mode 100644 src/pkg-style/static/icons/mic.png create mode 100644 src/pkg-style/static/icons/miniapp.png create mode 100644 src/pkg-style/static/icons/notebook.png create mode 100644 src/pkg-style/static/icons/notes.png create mode 100644 src/pkg-style/static/icons/orange-fruit.png create mode 100644 src/pkg-style/static/icons/papers.png create mode 100644 src/pkg-style/static/icons/pear.png create mode 100644 src/pkg-style/static/icons/pencil.png create mode 100644 src/pkg-style/static/icons/persona.png create mode 100644 src/pkg-style/static/icons/plane.png create mode 100644 src/pkg-style/static/icons/planet.png create mode 100644 src/pkg-style/static/icons/resume.png create mode 100644 src/pkg-style/static/icons/scan.png create mode 100644 src/pkg-style/static/icons/script.png create mode 100644 src/pkg-style/static/icons/selfbook.png create mode 100644 src/pkg-style/static/icons/shield.png create mode 100644 src/pkg-style/static/icons/shrimp.png create mode 100644 src/pkg-style/static/icons/store.png create mode 100644 src/pkg-style/static/icons/suitcase.png create mode 100644 src/pkg-style/static/icons/vinyl.png create mode 100644 src/pkg-style/static/icons/wework.png create mode 100644 src/pkg-style/static/icons/wordbook.png create mode 100644 src/pkg-style/style/showcase.scss create mode 100644 src/stores/cardStyle.ts create mode 100644 src/utils/image/errors.ts create mode 100644 src/utils/image/history.ts create mode 100644 src/utils/image/name-collision.ts create mode 100644 src/utils/image/naming.ts create mode 100644 src/utils/pane-refresh.ts create mode 100644 src/utils/z-index.ts create mode 100644 vite.config.ts.timestamp-1790161029749-4ba3e4a744878.mjs create mode 100644 vite.config.ts.timestamp-1790180057043-fe9dc0aae1d75.mjs create mode 100644 vite.config.ts.timestamp-1790180092082-e46dc62569487.mjs create mode 100644 vite.config.ts.timestamp-1790180142431-b740a0be265d.mjs create mode 100644 vite.config.ts.timestamp-1790180224337-1a90acfcfcbd5.mjs create mode 100644 vite.config.ts.timestamp-1790180269688-60bc6316745e5.mjs create mode 100644 vite.config.ts.timestamp-1790180300386-7432195a9a7d1.mjs diff --git a/components.d.ts b/components.d.ts index ad18355..4f85df3 100644 --- a/components.d.ts +++ b/components.d.ts @@ -7,24 +7,36 @@ export {} declare module 'vue' { export interface GlobalComponents { + CardTile: typeof import('./src/components/card/CardTile.vue')['default'] Confetti: typeof import('./src/components/Confetti.vue')['default'] CountUp: typeof import('./src/components/CountUp.vue')['default'] + CouponCard: typeof import('./src/components/coupon/CouponCard.vue')['default'] EmptyState: typeof import('./src/components/EmptyState.vue')['default'] + MineDrawers: typeof import('./src/components/mine/MineDrawers.vue')['default'] PaneLibrary: typeof import('./src/components/home/PaneLibrary.vue')['default'] PaneMine: typeof import('./src/components/home/PaneMine.vue')['default'] + PaneRefresher: typeof import('./src/components/home/PaneRefresher.vue')['default'] PaneWorkbench: typeof import('./src/components/home/PaneWorkbench.vue')['default'] + PromoCodeInput: typeof import('./src/components/member/PromoCodeInput.vue')['default'] QuotaBar: typeof import('./src/components/vip/QuotaBar.vue')['default'] QuotaGate: typeof import('./src/components/vip/QuotaGate.vue')['default'] + SeatMap: typeof import('./src/components/event/SeatMap.vue')['default'] Sticker: typeof import('./src/components/Sticker.vue')['default'] TabBar: typeof import('./src/components/TabBar.vue')['default'] TabIcon: typeof import('./src/components/TabIcon.vue')['default'] + ToolIdle: typeof import('./src/components/tool/ToolIdle.vue')['default'] + ToolPage: typeof import('./src/components/tool/ToolPage.vue')['default'] + ToolRunning: typeof import('./src/components/tool/ToolRunning.vue')['default'] + ToolSliderRow: typeof import('./src/components/tool/ToolSliderRow.vue')['default'] VipCard: typeof import('./src/components/vip/VipCard.vue')['default'] VipDock: typeof import('./src/components/vip/VipDock.vue')['default'] VipFloatAd: typeof import('./src/components/vip/VipFloatAd.vue')['default'] WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default'] + WdDatetimePicker: typeof import('wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue')['default'] WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default'] WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default'] WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default'] + WdSwitch: typeof import('wot-design-uni/components/wd-switch/wd-switch.vue')['default'] WdTextarea: typeof import('wot-design-uni/components/wd-textarea/wd-textarea.vue')['default'] } } diff --git a/scripts/selfcheck-naming.mjs b/scripts/selfcheck-naming.mjs new file mode 100644 index 0000000..5ab8181 --- /dev/null +++ b/scripts/selfcheck-naming.mjs @@ -0,0 +1,71 @@ +/** + * A2 自检脚本(可复现):验证「同一秒内两个同名任务 → 两个不等的 savedName」 + * + * 直接加载生产代码 `src/utils/image/name-collision.ts`(零依赖纯函数), + * 由 Node 原生类型剥离执行,无需打包工具: + * + * node scripts/selfcheck-naming.mjs + * + * 结果同时打印到终端并写入 `scripts/selfcheck-naming.log`(UTF-8), + * 避免 Windows 控制台代码页把中文输出弄成乱码。 + * 模拟 `core.ts#saveResult` 的去冲突步骤: + * 候选名 + 「当天历史 ∪ 本次会话已用名」集合 → dedupeName → 命中则追加 -2、-3。 + */ +import { writeFileSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, join } from 'node:path' +import { dedupeName } from '../src/utils/image/name-collision.ts' + +const lines = [] +let failed = 0 +function assert(cond, msg) { + const line = `${cond ? 'ok ' : 'FAIL'}: ${msg}` + lines.push(line) + if (!cond) + failed++ +} + +// —— 核心场景:同一秒、同工具、同原图,连续产出两次 —— +const candidate = '去除背景-IMG_2043-20260918153012.png' +const taken = [] + +const n1 = dedupeName(candidate, taken) +taken.push(n1) +const n2 = dedupeName(candidate, taken) +taken.push(n2) + +assert(n1 === candidate, `第一次产出保持干净格式:${n1}`) +assert(n2 !== n1, `两次产出文件名不相等:${n1} vs ${n2}`) +assert(n2 === '去除背景-IMG_2043-20260918153012-2.png', `第二次追加 -2:${n2}`) + +// —— 边界:时间戳(14 位数字)绝不能被误判成 `-N` 计数器 —— +assert(n2.endsWith('-20260918153012-2.png'), '时间戳未被当作计数器截断') + +// —— 边界:第三次继续递增 —— +const n3 = dedupeName(candidate, taken) +assert(n3 === '去除背景-IMG_2043-20260918153012-3.png', `第三次追加 -3:${n3}`) + +// —— 边界:主干已带 -N 后缀时从 N+1 起,避免出现 xxx-2-2 —— +assert(dedupeName('x-2.png', ['x-2.png']) === 'x-3.png', '已带后缀时递增不叠加(-2 → -3)') + +// —— 边界:无冲突时原样返回(正常路径不改名) —— +assert(dedupeName('a.png', []) === 'a.png', '无冲突原样返回') + +// —— 边界:无扩展名的候选 —— +assert(dedupeName('plain', ['plain']) === 'plain-2', '无扩展名时追加 -2') + +lines.push('') +lines.push(failed ? `${failed} check(s) FAILED` : 'ALL CHECKS PASSED') + +const out = lines.join('\n') +// eslint-disable-next-line no-console +console.log(out) +try { + const here = dirname(fileURLToPath(import.meta.url)) + writeFileSync(join(here, 'selfcheck-naming.log'), `${out}\n`, 'utf8') +} +catch { + /* 忽略:写日志失败不影响自检结论 */ +} + +process.exit(failed ? 1 : 0) diff --git a/src/App.vue b/src/App.vue index c79c8fb..e8c1cd9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -20,6 +20,12 @@ page { --tb-text: #3d2a1e; --tb-text-2: #9a7b65; --tb-border: #ffe3d3; + /* 卡片质感 token(R2-1):描边高光 + 内高光 + 三档阴影分层。色系不新增 */ + --tb-card-line: rgba(255, 195, 155, 0.55); + --tb-card-hi: rgba(255, 255, 255, 0.92); + --tb-shadow-1: 0 2rpx 6rpx rgba(107, 47, 15, 0.05), 0 10rpx 24rpx rgba(107, 47, 15, 0.08); + --tb-shadow-2: 0 3rpx 10rpx rgba(107, 47, 15, 0.05), 0 16rpx 38rpx rgba(107, 47, 15, 0.1); + --tb-shadow-3: 0 4rpx 12rpx rgba(107, 47, 15, 0.06), 0 22rpx 52rpx rgba(107, 47, 15, 0.13); /* 撞色点缀 */ --tb-mint: #3ecfb2; --tb-lemon: #ffc53d; @@ -68,6 +74,30 @@ page { opacity: 0.92; } +/* 卡片点击热区(P3):承接 tap 的原生 view 包裹层。 + 撑满网格单元高度,让同排 CardTile 视觉等高;子卡 flex 撑满。 + 注:子卡 .ct 自带 overflow:hidden(自动最小尺寸已为 0),故 min-width:0 只需在包裹层声明一次。 */ +.cttap { + display: flex; + min-width: 0; + /* 显式撑满:grid/flex 单元格里不允许出现"卡片比格子窄"的留白(P5 用户反馈②) */ + width: 100%; + align-items: stretch; +} +/* 缺陷 A 修复:MP 下自定义组件宿主(如 )会在 `.cttap` 与 `.ct` 之间包一层, + 使 `.cttap > .ct` 这个**子选择器永不匹配**(H5 单根组件就地渲染、无宿主包裹 → 只在 H5 生效, + H5 会对本 bug 假性通过)。宿主作为 flex 项若不显式撑满,主尺寸退化为 max-content + → 卡片宽度塌成「最长 nowrap 行」内容宽(≈4 个中文字)。 + ⚠️ MP 端宿主撑满**不能**在这里用 `.cttap > *` 兜底 —— WXSS 不支持通配符 `*`, + 真机开发者工具直接报「app.wxss(x:x): error at token '*'」,整个 app.wxss 编译失败 + (uni build EXIT=0 ≠ 微信工具链可编译)。MP 宿主撑满改由 CardTile.wxss 内的 + `:host` 规则承担(见 CardTile.vue + + diff --git a/src/components/coupon/CouponCard.vue b/src/components/coupon/CouponCard.vue new file mode 100644 index 0000000..44ceb92 --- /dev/null +++ b/src/components/coupon/CouponCard.vue @@ -0,0 +1,274 @@ + + + + + diff --git a/src/components/event/SeatMap.vue b/src/components/event/SeatMap.vue new file mode 100644 index 0000000..6a71417 --- /dev/null +++ b/src/components/event/SeatMap.vue @@ -0,0 +1,1004 @@ + + + + + diff --git a/src/components/home/PaneLibrary.vue b/src/components/home/PaneLibrary.vue index e0367f3..9bde218 100644 --- a/src/components/home/PaneLibrary.vue +++ b/src/components/home/PaneLibrary.vue @@ -1,44 +1,143 @@ - + - + diff --git a/src/components/mine/MineDrawers.vue b/src/components/mine/MineDrawers.vue new file mode 100644 index 0000000..0ba7ffa --- /dev/null +++ b/src/components/mine/MineDrawers.vue @@ -0,0 +1,948 @@ + + + + + diff --git a/src/components/tool/ToolIdle.vue b/src/components/tool/ToolIdle.vue new file mode 100644 index 0000000..a93b8db --- /dev/null +++ b/src/components/tool/ToolIdle.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/components/tool/ToolPage.vue b/src/components/tool/ToolPage.vue new file mode 100644 index 0000000..60f3e3d --- /dev/null +++ b/src/components/tool/ToolPage.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/components/tool/ToolRunning.vue b/src/components/tool/ToolRunning.vue new file mode 100644 index 0000000..eca6a66 --- /dev/null +++ b/src/components/tool/ToolRunning.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/src/components/tool/ToolSliderRow.vue b/src/components/tool/ToolSliderRow.vue new file mode 100644 index 0000000..fa84eff --- /dev/null +++ b/src/components/tool/ToolSliderRow.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/src/components/vip/QuotaBar.vue b/src/components/vip/QuotaBar.vue index 5686508..bf6a054 100644 --- a/src/components/vip/QuotaBar.vue +++ b/src/components/vip/QuotaBar.vue @@ -13,6 +13,7 @@ import type { ToolQuota } from '@/api/quota' import { computed, onMounted, ref, watch } from 'vue' import { useQuotaStore } from '@/stores/quota' import { currentToolKey, fetchToolQuota, goBuyPack, goMemberCenter, lastConsumedQuota } from '@/utils/quota' +import { Z } from '@/utils/z-index' const props = withDefaults(defineProps<{ toolKey?: string @@ -84,7 +85,7 @@ function buyMember() { @@ -142,7 +143,6 @@ function buyMember() { diff --git a/src/pages/mine/profile.vue b/src/pages/mine/profile.vue index 7e17ac5..1c3357e 100644 --- a/src/pages/mine/profile.vue +++ b/src/pages/mine/profile.vue @@ -5,6 +5,7 @@ import Sticker from '@/components/Sticker.vue' import { useUserStore } from '@/stores/user' import { AVATAR_PRESETS, presetOf } from '@/utils/avatar' import { navPadTop } from '@/utils/safearea' +import { Z } from '@/utils/z-index' const userStore = useUserStore() /** 导航栏顶部留白:MP 用真实状态栏高度 */ @@ -13,6 +14,8 @@ const navPad = navPadTop() const nickname = ref('') const avatarUrl = ref('') const saving = ref(false) +/** 微信头像上传中 */ +const uploading = ref(false) function syncFromStore() { const u = userStore.user @@ -31,6 +34,34 @@ function pickAvatar(key: string) { avatarUrl.value = key } +/** + * 微信头像(MP): + + + {{ '默认头像' }} + - + diff --git a/src/pages/tools/image/annotate.vue b/src/pages/tools/image/annotate.vue index 162edff..edeb32b 100644 --- a/src/pages/tools/image/annotate.vue +++ b/src/pages/tools/image/annotate.vue @@ -76,6 +76,14 @@ async function initCanvas(cssW: number, cssH: number) { el.height = ch * dpr canvasNode = el ctx = el.getContext('2d') + // ⚠️ H5 专属:uni-h5 运行时 `initHidpi()` 会 monkey-patch `CanvasRenderingContext2D.prototype`, + // 对所有 `__hidpi__ === true` 的 context 把绘制坐标(fillRect/drawImage/fillText/arc/...)自动 + // ×devicePixelRatio;uni 的 canvas 组件(hidpi 默认 true)会给本内层 canvas 的 ctx 打上该标记。 + // 本页的 逻辑坐标→高分辨率位图 映射已由下面的 `scale(dpr, dpr)` 完成,若再叠加 uni 的 ×dpr 会变成 + // **dpr²**:DPR≥2 时编辑画布与「保存到相册」的导出图都会被裁(只剩左上角放大,DPR=3 时整幅全红)。 + // 故此处显式关掉 uni 的这层自动缩放;用条件编译隔离,**MP 端不受影响**(MP 无此补丁)。 + if (ctx) + (ctx as any).__hidpi__ = false ctx?.scale(dpr, dpr) } resolve() diff --git a/src/pages/tools/image/avatarfx.vue b/src/pages/tools/image/avatarfx.vue index 547d76e..48997b3 100644 --- a/src/pages/tools/image/avatarfx.vue +++ b/src/pages/tools/image/avatarfx.vue @@ -3,6 +3,7 @@ import type { FxShape } from '@/utils/image/avatarfx' import { onReady } from '@dcloudio/uni-app' import { computed, ref } from 'vue' import Sticker from '@/components/Sticker.vue' +import ToolSliderRow from '@/components/tool/ToolSliderRow.vue' import VipDock from '@/components/vip/VipDock.vue' import { AVATAR_EFFECTS, drawEffect, drawPhoto } from '@/utils/image/avatarfx' import { beginDraw, bindImageCanvas, chooseOneImage, exportFile, loadImage, saveResult } from '@/utils/image/core' @@ -182,35 +183,29 @@ function goBack() { - - 照片缩放 - - - - 描边粗细 - - diff --git a/src/pages/tools/image/collage.vue b/src/pages/tools/image/collage.vue index b89fdb4..3ad887e 100644 --- a/src/pages/tools/image/collage.vue +++ b/src/pages/tools/image/collage.vue @@ -1,6 +1,7 @@ diff --git a/src/pages/tools/image/qrcode.vue b/src/pages/tools/image/qrcode.vue index fe39f9e..92831ac 100644 --- a/src/pages/tools/image/qrcode.vue +++ b/src/pages/tools/image/qrcode.vue @@ -1,20 +1,68 @@