分享功能和资质文件展示

This commit is contained in:
2026-07-28 00:31:31 +08:00
parent a49d8d99b6
commit 15c35c49de
7 changed files with 90 additions and 20 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 KiB

@@ -2,4 +2,6 @@ export default definePageConfig({
navigationBarTitleText: '我的', navigationBarTitleText: '我的',
enablePullDownRefresh: true, enablePullDownRefresh: true,
backgroundTextStyle: 'dark', backgroundTextStyle: 'dark',
enableShareAppMessage: true,
enableShareTimeline: true,
}); });
+32 -3
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { View, Text, Image, Button, Input, ScrollView } from '@tarojs/components'; import { View, Text, Image, Button, Input, ScrollView } from '@tarojs/components';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro'; import Taro, { useDidShow, usePullDownRefresh, useShareAppMessage, useShareTimeline } from '@tarojs/taro';
import { import {
BRAND_LOGO_MARK_URL, BRAND_LOGO_MARK_URL,
QUALIFICATION_DISCLOSURE_URL, QUALIFICATION_DISCLOSURE_URL,
@@ -9,6 +9,7 @@ import {
} from '@dukang/shared-types'; } from '@dukang/shared-types';
import PageShell from '../../components/PageShell'; import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader'; import TabMainHeader from '../../components/TabMainHeader';
import WechatShareReady from '../../components/WechatShareReady';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar'; import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import { goLogin } from '../../lib/auth-nav'; import { goLogin } from '../../lib/auth-nav';
import { bindWechatForUser } from '../../lib/wechat-auth'; import { bindWechatForUser } from '../../lib/wechat-auth';
@@ -22,6 +23,11 @@ import {
} from '../../lib/mini-wechat-profile'; } from '../../lib/mini-wechat-profile';
import { isLoggedIn, logout, request, toast, type UserProfile } from '../../lib/api'; import { isLoggedIn, logout, request, toast, type UserProfile } from '../../lib/api';
import { isWechatEnv } from '../../lib/weixin'; import { isWechatEnv } from '../../lib/weixin';
import {
DEFAULT_SHARE_DESC,
DEFAULT_SHARE_TITLE,
toWeappShareMessage,
} from '../../lib/wechat-share';
const ORDER_SHORTCUTS = [ const ORDER_SHORTCUTS = [
{ tab: 'pending_pay', icon: '付', label: '待付款' }, { tab: 'pending_pay', icon: '付', label: '待付款' },
@@ -132,6 +138,21 @@ export default function MinePage() {
.catch(() => setWxAuthorize(true)); .catch(() => setWxAuthorize(true));
}, []); }, []);
const sharePayload = useMemo(
() => ({
title: '杜康好客 · 我的',
desc: DEFAULT_SHARE_DESC,
path: '/pages/mine/index',
}),
[],
);
useShareAppMessage(() => toWeappShareMessage(sharePayload));
useShareTimeline(() => ({
title: sharePayload.title || DEFAULT_SHARE_TITLE,
query: '',
}));
async function ensureWechatBound(): Promise<boolean> { async function ensureWechatBound(): Promise<boolean> {
if (profile?.hasWechat) return true; if (profile?.hasWechat) return true;
if (!wxAuthorize) { if (!wxAuthorize) {
@@ -279,6 +300,7 @@ export default function MinePage() {
if (!authed) { if (!authed) {
return ( return (
<PageShell variant="tab" className="mine-page no-tab-header"> <PageShell variant="tab" className="mine-page no-tab-header">
<WechatShareReady payload={sharePayload} />
<TabMainHeader title="我的" /> <TabMainHeader title="我的" />
<View className="mine-header"> <View className="mine-header">
<View className="mine-header-texture" /> <View className="mine-header-texture" />
@@ -331,6 +353,7 @@ export default function MinePage() {
return ( return (
<PageShell variant="tab" className="mine-page no-tab-header"> <PageShell variant="tab" className="mine-page no-tab-header">
<WechatShareReady payload={sharePayload} />
<TabMainHeader title="我的" /> <TabMainHeader title="我的" />
<View className="mine-header"> <View className="mine-header">
<View className="mine-header-texture" /> <View className="mine-header-texture" />
@@ -533,7 +556,13 @@ export default function MinePage() {
className="mine-qualification-mask" className="mine-qualification-mask"
onClick={() => setQualificationOpen(false)} onClick={() => setQualificationOpen(false)}
> >
<ScrollView scrollY className="mine-qualification-scroll" enhanced showScrollbar> <ScrollView
scrollY
className="mine-qualification-scroll"
style={{ height: '100%' }}
enhanced
showScrollbar
>
<Image <Image
className="mine-qualification-img" className="mine-qualification-img"
src={QUALIFICATION_DISCLOSURE_URL} src={QUALIFICATION_DISCLOSURE_URL}
@@ -2,4 +2,6 @@ export default definePageConfig({
navigationBarTitleText: '门店', navigationBarTitleText: '门店',
enablePullDownRefresh: true, enablePullDownRefresh: true,
backgroundTextStyle: 'dark', backgroundTextStyle: 'dark',
enableShareAppMessage: true,
enableShareTimeline: true,
}); });
+23 -1
View File
@@ -1,8 +1,9 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { View, Text, Image, Input } from '@tarojs/components'; import { View, Text, Image, Input } from '@tarojs/components';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro'; import Taro, { useDidShow, usePullDownRefresh, useShareAppMessage, useShareTimeline } from '@tarojs/taro';
import PageShell from '../../components/PageShell'; import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader'; import TabMainHeader from '../../components/TabMainHeader';
import WechatShareReady from '../../components/WechatShareReady';
import RegionPicker from '../../components/RegionPicker'; import RegionPicker from '../../components/RegionPicker';
import CategoryPicker, { import CategoryPicker, {
EMPTY_CATEGORY, EMPTY_CATEGORY,
@@ -27,6 +28,11 @@ import {
import { FALLBACK_CITY_CODE } from '../../lib/product-images'; import { FALLBACK_CITY_CODE } from '../../lib/product-images';
import { formatDistanceMeters } from '../../lib/geo'; import { formatDistanceMeters } from '../../lib/geo';
import { request, toast } from '../../lib/api'; import { request, toast } from '../../lib/api';
import {
DEFAULT_SHARE_DESC,
DEFAULT_SHARE_TITLE,
toWeappShareMessage,
} from '../../lib/wechat-share';
type Store = { type Store = {
id: string; id: string;
@@ -176,8 +182,24 @@ export default function StoresPage() {
return parts.length ? `营业时间: ${parts.join('')}` : '营业时间: 10:00-22:00'; return parts.length ? `营业时间: ${parts.join('')}` : '营业时间: 10:00-22:00';
} }
const sharePayload = useMemo(
() => ({
title: '杜康好客门店',
desc: DEFAULT_SHARE_DESC,
path: '/pages/stores/index',
}),
[],
);
useShareAppMessage(() => toWeappShareMessage(sharePayload));
useShareTimeline(() => ({
title: sharePayload.title || DEFAULT_SHARE_TITLE,
query: '',
}));
return ( return (
<PageShell variant="tab" className="store-page no-tab-header"> <PageShell variant="tab" className="store-page no-tab-header">
<WechatShareReady payload={sharePayload} />
<TabMainHeader title="门店" /> <TabMainHeader title="门店" />
<View className="store-filter"> <View className="store-filter">
+18 -9
View File
@@ -505,31 +505,40 @@
z-index: 1200; z-index: 1200;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; width: 100%;
justify-content: center; height: 100%;
gap: 10px; padding: 0;
padding: 24px 16px; margin: 0;
background: rgba(0, 0, 0, 0.72); background: #000;
box-sizing: border-box; box-sizing: border-box;
} }
.mine-qualification-scroll { .mine-qualification-scroll {
flex: 1;
width: 100%; width: 100%;
max-width: 420px; height: 100%;
max-height: calc(86vh - 36px); max-width: none;
border-radius: 8px; max-height: none;
border-radius: 0;
overflow: hidden; overflow: hidden;
background: #fff; background: #000;
} }
.mine-qualification-img { .mine-qualification-img {
display: block; display: block;
width: 100%; width: 100%;
min-height: 100%;
pointer-events: none; pointer-events: none;
} }
.mine-qualification-hint { .mine-qualification-hint {
position: absolute;
left: 0;
right: 0;
bottom: calc(12px + env(safe-area-inset-bottom, 0px));
z-index: 1;
text-align: center; text-align: center;
font-size: 12px; font-size: 12px;
color: rgba(255, 255, 255, 0.82); color: rgba(255, 255, 255, 0.82);
pointer-events: none;
} }
@@ -1,9 +1,11 @@
/** /**
* 上传小程序「资质公示」静态图到 OSSstatic/mini-user/qualification-disclosure.png * 上传小程序「资质公示」静态图到 OSSstatic/mini-user/qualification-disclosure.png
* 用法(在 server/dukang-api: node scripts/upload-qualification-disclosure.mjs * 用法(在 server/dukang-api:
* node scripts/upload-qualification-disclosure.mjs [本地 png 路径]
* 也可设环境变量 QUALIFICATION_DISCLOSURE_LOCAL。
*/ */
import { readFileSync, existsSync } from 'fs'; import { readFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path'; import { resolve, dirname, isAbsolute } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { createRequire } from 'module'; import { createRequire } from 'module';
@@ -12,7 +14,6 @@ const OSS = require('ali-oss');
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
const apiRoot = resolve(__dirname, '..'); const apiRoot = resolve(__dirname, '..');
const repoRoot = resolve(apiRoot, '../..');
function loadEnvFile(path) { function loadEnvFile(path) {
if (!existsSync(path)) return {}; if (!existsSync(path)) return {};
@@ -49,10 +50,15 @@ if (!accessKeyId || !accessKeySecret || !bucket) {
process.exit(1); process.exit(1);
} }
const localFile = resolve( const argPath = process.argv[2]?.trim() || env.QUALIFICATION_DISCLOSURE_LOCAL?.trim() || '';
repoRoot, if (!argPath) {
'apps/mini-user/src/assets/qualification-disclosure.png', console.error(
'请传入本地 png 路径,例如:\n node scripts/upload-qualification-disclosure.mjs D:/tmp/qualification-disclosure.png',
); );
process.exit(1);
}
const localFile = isAbsolute(argPath) ? argPath : resolve(process.cwd(), argPath);
if (!existsSync(localFile)) { if (!existsSync(localFile)) {
console.error('本地文件不存在:', localFile); console.error('本地文件不存在:', localFile);
process.exit(1); process.exit(1);