feat: 搭建微信小程序展示端
- 初始化小程序工程配置与类型声明 - 增加首页、律所、律师列表、详情与历史页面 - 补充公共组件、运行时配置与示例素材
147
frontend_miniprogram/miniprogram/api/open.ts
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import type { FirmInfo, Lawyer } from '../types/card';
|
||||||
|
import { request } from '../utils/http';
|
||||||
|
|
||||||
|
interface OpenFirmResponse {
|
||||||
|
name: string;
|
||||||
|
logo: string;
|
||||||
|
heroImage: string;
|
||||||
|
intro: string;
|
||||||
|
hotlinePhone: string;
|
||||||
|
hqAddress: string;
|
||||||
|
hqLatitude: number;
|
||||||
|
hqLongitude: number;
|
||||||
|
officeCount: number;
|
||||||
|
lawyerCount: number;
|
||||||
|
officeList: string[];
|
||||||
|
practiceAreas: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OpenCardListItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
office: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
avatar: string;
|
||||||
|
specialties: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OpenCardDetailResponse {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
office: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
address: string;
|
||||||
|
avatar: string;
|
||||||
|
coverImage: string;
|
||||||
|
wechatQrImage: string;
|
||||||
|
bio: string;
|
||||||
|
specialties: string[];
|
||||||
|
firmName: string;
|
||||||
|
firmAddress: string;
|
||||||
|
firmLatitude: number;
|
||||||
|
firmLongitude: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFirmInfo(payload: OpenFirmResponse): FirmInfo {
|
||||||
|
return {
|
||||||
|
id: payload.name || 'firm',
|
||||||
|
name: payload.name || '',
|
||||||
|
logo: payload.logo || '',
|
||||||
|
intro: payload.intro || '',
|
||||||
|
hotlinePhone: payload.hotlinePhone || '',
|
||||||
|
hqAddress: payload.hqAddress || '',
|
||||||
|
hqLatitude: payload.hqLatitude || 0,
|
||||||
|
hqLongitude: payload.hqLongitude || 0,
|
||||||
|
officeCount: payload.officeCount || 0,
|
||||||
|
lawyerCount: payload.lawyerCount || 0,
|
||||||
|
heroImage: payload.heroImage || '',
|
||||||
|
officeList: payload.officeList || [],
|
||||||
|
practiceAreas: payload.practiceAreas || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toLawyer(payload: OpenCardListItem | OpenCardDetailResponse): Lawyer {
|
||||||
|
return {
|
||||||
|
id: String(payload.id),
|
||||||
|
name: payload.name || '',
|
||||||
|
title: payload.title || '',
|
||||||
|
office: payload.office || '',
|
||||||
|
phone: payload.phone || '',
|
||||||
|
email: payload.email || '',
|
||||||
|
address: 'address' in payload ? payload.address || '' : '',
|
||||||
|
avatar: payload.avatar || '',
|
||||||
|
coverImage: 'coverImage' in payload ? payload.coverImage || '' : '',
|
||||||
|
specialties: payload.specialties || [],
|
||||||
|
bio: 'bio' in payload ? payload.bio || '' : '',
|
||||||
|
wechatQrImage: 'wechatQrImage' in payload ? payload.wechatQrImage || '' : '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getFirmProfile(): Promise<FirmInfo> {
|
||||||
|
const payload = await request<OpenFirmResponse>({
|
||||||
|
url: '/api/open/firm/profile',
|
||||||
|
});
|
||||||
|
return toFirmInfo(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listLawyers(params: {
|
||||||
|
keyword?: string;
|
||||||
|
office?: string;
|
||||||
|
practiceArea?: string;
|
||||||
|
}): Promise<Lawyer[]> {
|
||||||
|
const query = Object.entries(params)
|
||||||
|
.filter(([, value]) => Boolean(value))
|
||||||
|
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value as string)}`)
|
||||||
|
.join('&');
|
||||||
|
const payload = await request<OpenCardListItem[]>({
|
||||||
|
url: `/api/open/cards${query ? `?${query}` : ''}`,
|
||||||
|
});
|
||||||
|
return payload.map((item) => toLawyer(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLawyerDetail(cardId: string, sourceType = 'DIRECT', shareFromCardId = ''): Promise<{
|
||||||
|
firm: FirmInfo;
|
||||||
|
lawyer: Lawyer;
|
||||||
|
}> {
|
||||||
|
const queryParts = [`sourceType=${encodeURIComponent(sourceType)}`];
|
||||||
|
if (shareFromCardId) {
|
||||||
|
queryParts.push(`shareFromCardId=${encodeURIComponent(shareFromCardId)}`);
|
||||||
|
}
|
||||||
|
const payload = await request<OpenCardDetailResponse>({
|
||||||
|
url: `/api/open/cards/${encodeURIComponent(cardId)}?${queryParts.join('&')}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
firm: {
|
||||||
|
id: payload.firmName || 'firm',
|
||||||
|
name: payload.firmName || '',
|
||||||
|
logo: '',
|
||||||
|
intro: '',
|
||||||
|
hotlinePhone: '',
|
||||||
|
hqAddress: payload.firmAddress || '',
|
||||||
|
hqLatitude: payload.firmLatitude || 0,
|
||||||
|
hqLongitude: payload.firmLongitude || 0,
|
||||||
|
officeCount: 0,
|
||||||
|
lawyerCount: 0,
|
||||||
|
heroImage: '',
|
||||||
|
officeList: [],
|
||||||
|
practiceAreas: [],
|
||||||
|
},
|
||||||
|
lawyer: toLawyer(payload),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function recordCardShare(cardId: string, sharePath: string): Promise<void> {
|
||||||
|
await request<void>({
|
||||||
|
url: `/api/open/cards/${encodeURIComponent(cardId)}/share`,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
shareChannel: 'WECHAT_FRIEND',
|
||||||
|
sharePath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
26
frontend_miniprogram/miniprogram/app.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
"pages/firm/index",
|
||||||
|
"pages/lawyer-list/index",
|
||||||
|
"pages/lawyer-detail/index",
|
||||||
|
"pages/history/index"
|
||||||
|
],
|
||||||
|
"window": {
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"backgroundTextStyle": "light",
|
||||||
|
"backgroundColor": "#f4f4f4"
|
||||||
|
},
|
||||||
|
"style": "v2",
|
||||||
|
"rendererOptions": {
|
||||||
|
"skyline": {
|
||||||
|
"defaultDisplayBlock": true,
|
||||||
|
"disableABTest": true,
|
||||||
|
"sdkVersionBegin": "3.0.0",
|
||||||
|
"sdkVersionEnd": "15.255.255"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"componentFramework": "glass-easel",
|
||||||
|
"sitemapLocation": "sitemap.json",
|
||||||
|
"lazyCodeLoading": "requiredComponents"
|
||||||
|
}
|
||||||
201
frontend_miniprogram/miniprogram/app.less
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/**
|
||||||
|
* Law Firm Digital Card - Design System
|
||||||
|
* 简约、扁平、现代化风格
|
||||||
|
*/
|
||||||
|
|
||||||
|
page {
|
||||||
|
/* --- 核心色彩系统 (Color Palette) --- */
|
||||||
|
|
||||||
|
/* 主色调:勃艮第红 - 传递权威、庄重、正义 */
|
||||||
|
--primary-color: #8E2230;
|
||||||
|
--primary-light: #B86A74;
|
||||||
|
/* 用于 hover 或浅色背景 */
|
||||||
|
--primary-dark: #5C0D15;
|
||||||
|
|
||||||
|
/* 强调色:金色 - 传递高端、品质 */
|
||||||
|
--accent-color: #D4AF37;
|
||||||
|
--accent-light: #dfc466;
|
||||||
|
|
||||||
|
/* 中性色系统 */
|
||||||
|
--text-main: #1A1A1A;
|
||||||
|
/* 主要文字,接近纯黑 */
|
||||||
|
--text-secondary: #595959;
|
||||||
|
/* 次要文字,深灰 */
|
||||||
|
--text-tertiary: #8C8C8C;
|
||||||
|
/* 辅助文字,浅灰 */
|
||||||
|
--text-placeholder: #BFBFBF;
|
||||||
|
|
||||||
|
/* 背景色 */
|
||||||
|
--bg-page: #F5F7FA;
|
||||||
|
/* 页面底色,极浅的蓝灰 */
|
||||||
|
--bg-card: #FFFFFF;
|
||||||
|
/* 卡片背景,纯白 */
|
||||||
|
--bg-surface: #F9FAFC;
|
||||||
|
/* 次级表面颜色 */
|
||||||
|
|
||||||
|
/* 分割线与边框 */
|
||||||
|
--border-color: #E8E8E8;
|
||||||
|
--border-radius-base: 12rpx;
|
||||||
|
--border-radius-lg: 16rpx;
|
||||||
|
--border-radius-sm: 8rpx;
|
||||||
|
|
||||||
|
/* --- 排版系统 (Typography) --- */
|
||||||
|
--font-size-xs: 20rpx;
|
||||||
|
--font-size-sm: 24rpx;
|
||||||
|
--font-size-base: 28rpx;
|
||||||
|
--font-size-lg: 32rpx;
|
||||||
|
--font-size-xl: 36rpx;
|
||||||
|
--font-size-xxl: 40rpx;
|
||||||
|
|
||||||
|
--font-weight-regular: 400;
|
||||||
|
--font-weight-medium: 500;
|
||||||
|
--font-weight-bold: 600;
|
||||||
|
|
||||||
|
/* --- 间距 (Spacing) --- */
|
||||||
|
--spacing-xs: 8rpx;
|
||||||
|
--spacing-sm: 16rpx;
|
||||||
|
--spacing-md: 24rpx;
|
||||||
|
--spacing-lg: 32rpx;
|
||||||
|
--spacing-xl: 48rpx;
|
||||||
|
|
||||||
|
/* --- 阴影 (Shadows) --- */
|
||||||
|
--shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||||
|
--shadow-base: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
|
--shadow-lg: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
/* 全局设置 */
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
|
||||||
|
background-color: var(--bg-page);
|
||||||
|
color: var(--text-main);
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- 布局工具类 (Layout Utilities) --- */
|
||||||
|
|
||||||
|
.container-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: var(--bg-page);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flexbox Helpers */
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-between {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-wrap {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spacing Helpers */
|
||||||
|
.mt-sm {
|
||||||
|
margin-top: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-md {
|
||||||
|
margin-top: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-lg {
|
||||||
|
margin-top: var(--spacing-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-sm {
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-md {
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-lg {
|
||||||
|
margin-bottom: var(--spacing-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text Utilities */
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-primary {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-secondary {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-accent {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-bold {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common Components */
|
||||||
|
.card {
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section Title - Modern Style */
|
||||||
|
.section-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
color: var(--text-main);
|
||||||
|
position: relative;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 4rpx;
|
||||||
|
bottom: 4rpx;
|
||||||
|
width: 6rpx;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safe Area styling for bottom navigation */
|
||||||
|
.safe-area-bottom {
|
||||||
|
padding-bottom: constant(safe-area-inset-bottom);
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
6
frontend_miniprogram/miniprogram/app.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
App<IAppOption>({
|
||||||
|
globalData: {},
|
||||||
|
onLaunch() {
|
||||||
|
// 可在此扩展启动逻辑
|
||||||
|
},
|
||||||
|
});
|
||||||
BIN
frontend_miniprogram/miniprogram/assets/images/avatar_1.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/avatar_2.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/avatar_3.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/avatar_4.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/avatar_5.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/hero.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/hero_v2.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
frontend_miniprogram/miniprogram/assets/images/logo.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
frontend_miniprogram/miniprogram/assets/qr/qr_1.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend_miniprogram/miniprogram/assets/qr/qr_2.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend_miniprogram/miniprogram/assets/qr/qr_3.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend_miniprogram/miniprogram/assets/qr/qr_4.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend_miniprogram/miniprogram/assets/qr/qr_5.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
.action-dock {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx var(--spacing-lg) calc(16rpx + env(safe-area-inset-bottom));
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-top: 1rpx solid var(--border-color);
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 20rpx;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
line-height: inherit;
|
||||||
|
border-radius: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
/* Emoji size */
|
||||||
|
margin-bottom: 4rpx;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:active .icon {
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-text {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Component({
|
||||||
|
methods: {
|
||||||
|
handleAction(event: WechatMiniprogram.TouchEvent) {
|
||||||
|
const action = event.currentTarget.dataset.action as string;
|
||||||
|
this.triggerEvent('action', { action });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<view class="action-dock">
|
||||||
|
<view class="action-item" data-action="save" bindtap="handleAction">
|
||||||
|
<text class="icon">存</text>
|
||||||
|
<text>收下名片</text>
|
||||||
|
</view>
|
||||||
|
<button class="action-item action-btn" open-type="share">
|
||||||
|
<text class="icon">享</text>
|
||||||
|
<text>分享名片</text>
|
||||||
|
</button>
|
||||||
|
<view class="action-item" data-action="location" bindtap="handleAction">
|
||||||
|
<text class="icon">导</text>
|
||||||
|
<text>律所导航</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"navigation-bar": "/components/navigation-bar/navigation-bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Component({
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
type: String,
|
||||||
|
value: '#F4F4F4',
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
value: '#1f1f1f',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<navigation-bar
|
||||||
|
title="{{title}}"
|
||||||
|
back="{{back}}"
|
||||||
|
color="{{color}}"
|
||||||
|
background="{{background}}"
|
||||||
|
></navigation-bar>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
.empty-wrap {
|
||||||
|
padding: 140rpx 40rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
background: var(--bg-surface);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 36rpx;
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Component({
|
||||||
|
properties: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
value: '暂无数据',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<view class="empty-wrap">
|
||||||
|
<text class="empty-icon">∅</text>
|
||||||
|
<text class="empty-text">{{text}}</text>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
.filter-wrap {
|
||||||
|
display: flex;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 0 24rpx 16rpx;
|
||||||
|
background: var(--bg-page);
|
||||||
|
/* Use variable */
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
height: 84rpx;
|
||||||
|
padding: 0 18rpx;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
border: 1rpx solid var(--border-color);
|
||||||
|
/* Use variable */
|
||||||
|
background: #fff;
|
||||||
|
/* Card bg */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
picker {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
/* Use variable */
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--text-main);
|
||||||
|
/* Use variable */
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
color: var(--text-placeholder);
|
||||||
|
/* Use variable */
|
||||||
|
font-size: 20rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
Component({
|
||||||
|
properties: {
|
||||||
|
officeOptions: {
|
||||||
|
type: Array,
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
areaOptions: {
|
||||||
|
type: Array,
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
selectedOffice: {
|
||||||
|
type: String,
|
||||||
|
value: '所有办公机构',
|
||||||
|
},
|
||||||
|
selectedArea: {
|
||||||
|
type: String,
|
||||||
|
value: '全部专业领域',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleOfficeChange(event: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||||
|
const officeOptions = this.properties.officeOptions as string[];
|
||||||
|
const index = Number(event.detail.value);
|
||||||
|
const value = officeOptions[index] || officeOptions[0] || '所有办公机构';
|
||||||
|
this.triggerEvent('officechange', { value, index });
|
||||||
|
},
|
||||||
|
handleAreaChange(event: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||||
|
const areaOptions = this.properties.areaOptions as string[];
|
||||||
|
const index = Number(event.detail.value);
|
||||||
|
const value = areaOptions[index] || areaOptions[0] || '全部专业领域';
|
||||||
|
this.triggerEvent('areachange', { value, index });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<view class="filter-wrap">
|
||||||
|
<picker mode="selector" range="{{officeOptions}}" bindchange="handleOfficeChange">
|
||||||
|
<view class="filter-item">
|
||||||
|
<text class="label">机构</text>
|
||||||
|
<text class="value">{{selectedOffice}}</text>
|
||||||
|
<text class="arrow">▾</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
<picker mode="selector" range="{{areaOptions}}" bindchange="handleAreaChange">
|
||||||
|
<view class="filter-item">
|
||||||
|
<text class="label">领域</text>
|
||||||
|
<text class="value">{{selectedArea}}</text>
|
||||||
|
<text class="arrow">▾</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"component": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
.lawyer-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lawyer-card:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 100rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4rpx solid var(--bg-page);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: var(--spacing-sm);
|
||||||
|
background: var(--bg-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-main);
|
||||||
|
margin-right: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: var(--primary-color);
|
||||||
|
background: rgba(142, 34, 48, 0.08);
|
||||||
|
/* Primary opacity */
|
||||||
|
padding: 2rpx 10rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.office {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
background: var(--bg-page);
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-more {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
padding: 4rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-col {
|
||||||
|
margin-left: var(--spacing-md);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consult-btn {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--primary-color);
|
||||||
|
border: 1rpx solid var(--primary-color);
|
||||||
|
padding: 6rpx 20rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
specialtiesText: '',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
lawyer: {
|
||||||
|
type: Object,
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
showOffice: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
observers: {
|
||||||
|
lawyer(lawyer: { specialties?: string[] } | null) {
|
||||||
|
const specialties =
|
||||||
|
lawyer && Array.isArray(lawyer.specialties) ? lawyer.specialties : [];
|
||||||
|
this.setData({
|
||||||
|
specialties, // Expose array for wx:for
|
||||||
|
specialtiesText: specialties.join(' | '),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTap() {
|
||||||
|
const lawyer = this.properties.lawyer as { id?: string } | null;
|
||||||
|
this.triggerEvent('select', {
|
||||||
|
id: lawyer && typeof lawyer.id === 'string' ? lawyer.id : '',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<view class="lawyer-card" bindtap="handleTap">
|
||||||
|
<image class="avatar" src="{{lawyer.avatar}}" mode="aspectFill"></image>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="header-row">
|
||||||
|
<text class="name">{{lawyer.name}}</text>
|
||||||
|
<text class="title">{{lawyer.title}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<text wx:if="{{showOffice}}" class="office">{{lawyer.office}}</text>
|
||||||
|
|
||||||
|
<view class="tags-row">
|
||||||
|
<text class="tag" wx:for="{{specialties}}" wx:key="*this" wx:if="{{index < 3}}">{{item}}</text>
|
||||||
|
<text class="tag-more" wx:if="{{specialties.length > 3}}">...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="action-col">
|
||||||
|
<text class="consult-btn">咨询</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"styleIsolation": "apply-shared",
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
.weui-navigation-bar {
|
||||||
|
--weui-FG-0:rgba(0,0,0,.9);
|
||||||
|
--height: 44px;
|
||||||
|
--left: 16px;
|
||||||
|
}
|
||||||
|
.weui-navigation-bar .android {
|
||||||
|
--height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar {
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--weui-FG-0);
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__inner {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: calc(var(--height) + env(safe-area-inset-top));
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: env(safe-area-inset-top);
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__left {
|
||||||
|
position: relative;
|
||||||
|
padding-left: var(--left);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__btn_goback_wrapper {
|
||||||
|
padding: 11px 18px 11px 16px;
|
||||||
|
margin: -11px -18px -11px -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__btn_goback_wrapper.weui-active {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__btn_goback {
|
||||||
|
font-size: 12px;
|
||||||
|
width: 12px;
|
||||||
|
height: 24px;
|
||||||
|
-webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
|
||||||
|
mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
|
||||||
|
-webkit-mask-size: cover;
|
||||||
|
mask-size: cover;
|
||||||
|
background-color: var(--weui-FG-0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__center {
|
||||||
|
font-size: 17px;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-navigation-bar__loading {
|
||||||
|
margin-right: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weui-loading {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: block;
|
||||||
|
background: transparent url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='80px' height='80px' viewBox='0 0 80 80' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3Eloading%3C/title%3E%3Cdefs%3E%3ClinearGradient x1='94.0869141%25' y1='0%25' x2='94.0869141%25' y2='90.559082%25' id='linearGradient-1'%3E%3Cstop stop-color='%23606060' stop-opacity='0' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3ClinearGradient x1='100%25' y1='8.67370605%25' x2='100%25' y2='90.6286621%25' id='linearGradient-2'%3E%3Cstop stop-color='%23606060' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' opacity='0.9'%3E%3Cg%3E%3Cpath d='M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 L40,73 C58.2253967,73 73,58.2253967 73,40 C73,21.7746033 58.2253967,7 40,7 L40,0 Z' fill='url(%23linearGradient-1)'%3E%3C/path%3E%3Cpath d='M40,0 L40,7 C21.7746033,7 7,21.7746033 7,40 C7,58.2253967 21.7746033,73 40,73 L40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z' fill='url(%23linearGradient-2)'%3E%3C/path%3E%3Ccircle id='Oval' fill='%23606060' cx='40.5' cy='3.5' r='3.5'%3E%3C/circle%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") no-repeat;
|
||||||
|
background-size: 100%;
|
||||||
|
margin-left: 0;
|
||||||
|
animation: loading linear infinite 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
from {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
Component({
|
||||||
|
options: {
|
||||||
|
multipleSlots: true // 在组件定义时的选项中启用多slot支持
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的属性列表
|
||||||
|
*/
|
||||||
|
properties: {
|
||||||
|
extClass: {
|
||||||
|
type: String,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
type: String,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
homeButton: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
animated: {
|
||||||
|
// 显示隐藏的时候opacity动画效果
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
show: {
|
||||||
|
// 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
|
||||||
|
type: Boolean,
|
||||||
|
value: true,
|
||||||
|
observer: '_showChange'
|
||||||
|
},
|
||||||
|
// back为true的时候,返回的页面深度
|
||||||
|
delta: {
|
||||||
|
type: Number,
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的初始数据
|
||||||
|
*/
|
||||||
|
data: {
|
||||||
|
displayStyle: ''
|
||||||
|
},
|
||||||
|
lifetimes: {
|
||||||
|
attached() {
|
||||||
|
const rect = wx.getMenuButtonBoundingClientRect()
|
||||||
|
wx.getSystemInfo({
|
||||||
|
success: (res) => {
|
||||||
|
const isAndroid = res.platform === 'android'
|
||||||
|
const isDevtools = res.platform === 'devtools'
|
||||||
|
this.setData({
|
||||||
|
ios: !isAndroid,
|
||||||
|
innerPaddingRight: `padding-right: ${res.windowWidth - rect.left}px`,
|
||||||
|
leftWidth: `width: ${res.windowWidth - rect.left }px`,
|
||||||
|
safeAreaTop: isDevtools || isAndroid ? `height: calc(var(--height) + ${res.safeArea.top}px); padding-top: ${res.safeArea.top}px` : ``
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 组件的方法列表
|
||||||
|
*/
|
||||||
|
methods: {
|
||||||
|
_showChange(show: boolean) {
|
||||||
|
const animated = this.data.animated
|
||||||
|
let displayStyle = ''
|
||||||
|
if (animated) {
|
||||||
|
displayStyle = `opacity: ${
|
||||||
|
show ? '1' : '0'
|
||||||
|
};transition:opacity 0.5s;`
|
||||||
|
} else {
|
||||||
|
displayStyle = `display: ${show ? '' : 'none'}`
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
displayStyle
|
||||||
|
})
|
||||||
|
},
|
||||||
|
back() {
|
||||||
|
const data = this.data
|
||||||
|
if (data.delta) {
|
||||||
|
wx.navigateBack({
|
||||||
|
delta: data.delta
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.triggerEvent('back', { delta: data.delta }, {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<view class="weui-navigation-bar {{extClass}}">
|
||||||
|
<view class="weui-navigation-bar__inner {{ios ? 'ios' : 'android'}}" style="color: {{color}}; background: {{background}}; {{displayStyle}}; {{innerPaddingRight}}; {{safeAreaTop}};">
|
||||||
|
|
||||||
|
<!-- 左侧按钮 -->
|
||||||
|
<view class='weui-navigation-bar__left' style="{{leftWidth}};">
|
||||||
|
<block wx:if="{{back || homeButton}}">
|
||||||
|
<!-- 返回上一页 -->
|
||||||
|
<block wx:if="{{back}}">
|
||||||
|
<view class="weui-navigation-bar__buttons weui-navigation-bar__buttons_goback">
|
||||||
|
<view
|
||||||
|
bindtap="back"
|
||||||
|
class="weui-navigation-bar__btn_goback_wrapper"
|
||||||
|
hover-class="weui-active"
|
||||||
|
hover-stay-time="100"
|
||||||
|
aria-role="button"
|
||||||
|
aria-label="返回"
|
||||||
|
>
|
||||||
|
<view class="weui-navigation-bar__button weui-navigation-bar__btn_goback"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<!-- 返回首页 -->
|
||||||
|
<block wx:if="{{homeButton}}">
|
||||||
|
<view class="weui-navigation-bar__buttons weui-navigation-bar__buttons_home">
|
||||||
|
<view
|
||||||
|
bindtap="home"
|
||||||
|
class="weui-navigation-bar__btn_home_wrapper"
|
||||||
|
hover-class="weui-active"
|
||||||
|
aria-role="button"
|
||||||
|
aria-label="首页"
|
||||||
|
>
|
||||||
|
<view class="weui-navigation-bar__button weui-navigation-bar__btn_home"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<slot name="left"></slot>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class='weui-navigation-bar__center'>
|
||||||
|
<view wx:if="{{loading}}" class="weui-navigation-bar__loading" aria-role="alert">
|
||||||
|
<view
|
||||||
|
class="weui-loading"
|
||||||
|
aria-role="img"
|
||||||
|
aria-label="加载中"
|
||||||
|
></view>
|
||||||
|
</view>
|
||||||
|
<block wx:if="{{title}}">
|
||||||
|
<text>{{title}}</text>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<slot name="center"></slot>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 右侧留空 -->
|
||||||
|
<view class='weui-navigation-bar__right'>
|
||||||
|
<slot name="right"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
16
frontend_miniprogram/miniprogram/config/runtime.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export type MiniProgramEnvVersion = 'develop' | 'trial' | 'release';
|
||||||
|
|
||||||
|
export const API_BASE_URL_OVERRIDE_KEY = 'api_base_url_override';
|
||||||
|
|
||||||
|
export interface TenantRuntimeConfig {
|
||||||
|
apiBaseUrlByEnv: Record<MiniProgramEnvVersion, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// develop 环境允许本地联调;trial/release 请替换为已备案且已配置到小程序后台“服务器域名”的 HTTPS 域名。
|
||||||
|
export const tenantRuntimeConfig: TenantRuntimeConfig = {
|
||||||
|
apiBaseUrlByEnv: {
|
||||||
|
develop: 'http://127.0.0.1:8112',
|
||||||
|
trial: 'https://trial-api.example.com',
|
||||||
|
release: 'https://api.example.com',
|
||||||
|
},
|
||||||
|
};
|
||||||
1
frontend_miniprogram/miniprogram/constants/storage.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const CARD_VIEW_HISTORY_KEY = 'card_view_history_v1';
|
||||||
102
frontend_miniprogram/miniprogram/data/mock.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import type { FirmInfo, Lawyer } from '../types/card';
|
||||||
|
|
||||||
|
export const firmInfo: FirmInfo = {
|
||||||
|
id: 'firm_xx',
|
||||||
|
name: 'XX律师事务所',
|
||||||
|
logo: '/assets/images/logo.png', // Keep path, but UI uses placeholder
|
||||||
|
heroImage: '/assets/images/hero_v2.png',
|
||||||
|
hotlinePhone: '13800138000',
|
||||||
|
hqAddress: '南京市江宁区紫金研创中心',
|
||||||
|
hqLatitude: 31.932, // Approximate for Jiangning Zijin
|
||||||
|
hqLongitude: 118.825,
|
||||||
|
officeCount: 4,
|
||||||
|
lawyerCount: 5,
|
||||||
|
officeList: ['南京总部', '北京分所', '上海分所', '深圳分所'],
|
||||||
|
practiceAreas: [
|
||||||
|
'民商事',
|
||||||
|
'婚姻家事',
|
||||||
|
'企业合规',
|
||||||
|
'公司法务',
|
||||||
|
'数字经济',
|
||||||
|
'破产法',
|
||||||
|
'私人财富管理',
|
||||||
|
'合同纠纷',
|
||||||
|
'劳动争议',
|
||||||
|
'知识产权',
|
||||||
|
],
|
||||||
|
intro:
|
||||||
|
'XX律师事务所是一家综合性律师事务所,长期聚焦民商事争议解决、公司治理与合规管理、婚姻家事与私人财富管理等方向。律所总部位于南京,面向企业与个人客户提供规范、专业、可持续的法律服务。\n\n截至目前,本所在多地设有分支办公室,拥有成熟的专业委员会体系与协同办案机制,已为大量企事业单位和个人客户提供法律顾问及专项法律服务。',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lawyers: Lawyer[] = [
|
||||||
|
{
|
||||||
|
id: 'lawyer_zhangsan',
|
||||||
|
name: '张三',
|
||||||
|
title: '高级合伙人',
|
||||||
|
office: '南京总部',
|
||||||
|
phone: '13800138000',
|
||||||
|
email: 'zhangsan@xx-law.com',
|
||||||
|
address: '南京市江宁区紫金研创中心',
|
||||||
|
avatar: '/assets/images/avatar_1.png',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: ['企业合规', '公司法务', '数字经济', '破产法'],
|
||||||
|
bio: '长期服务于企业客户,擅长企业合规体系建设、股权与治理结构优化、公司争议解决。',
|
||||||
|
wechatQrImage: '/assets/qr/qr_1.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lawyer_lisi',
|
||||||
|
name: '李四',
|
||||||
|
title: '资深律师',
|
||||||
|
office: '南京总部',
|
||||||
|
phone: '13800138001',
|
||||||
|
email: 'lisi@xx-law.com',
|
||||||
|
address: '南京市江宁区紫金研创中心',
|
||||||
|
avatar: '/assets/images/avatar_2.png',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: ['婚姻家事', '私人财富管理'],
|
||||||
|
bio: '专注婚姻家事和财富管理争议,注重非诉协商与诉讼策略并行。',
|
||||||
|
wechatQrImage: '/assets/qr/qr_2.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lawyer_wangwu',
|
||||||
|
name: '王五',
|
||||||
|
title: '律师',
|
||||||
|
office: '北京分所',
|
||||||
|
phone: '13800138002',
|
||||||
|
email: 'wangwu@xx-law.com',
|
||||||
|
address: '北京市朝阳区国贸CBD',
|
||||||
|
avatar: '/assets/images/avatar_3.png',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: ['民商事', '合同纠纷'],
|
||||||
|
bio: '擅长民商事纠纷案件办理,兼具庭审攻防与证据组织能力。',
|
||||||
|
wechatQrImage: '/assets/qr/qr_3.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lawyer_zhaoliu',
|
||||||
|
name: '赵六',
|
||||||
|
title: '律师',
|
||||||
|
office: '上海分所',
|
||||||
|
phone: '13800138003',
|
||||||
|
email: 'zhaoliu@xx-law.com',
|
||||||
|
address: '上海市浦东新区陆家嘴',
|
||||||
|
avatar: '/assets/images/avatar_4.png',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: ['劳动争议', '公司法务'],
|
||||||
|
bio: '长期服务成长型企业,熟悉劳动用工、合同管理和风险治理。',
|
||||||
|
wechatQrImage: '/assets/qr/qr_4.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lawyer_sunqi',
|
||||||
|
name: '孙七',
|
||||||
|
title: '律师',
|
||||||
|
office: '深圳分所',
|
||||||
|
phone: '13800138004',
|
||||||
|
email: 'sunqi@xx-law.com',
|
||||||
|
address: '深圳市福田区中心商务区',
|
||||||
|
avatar: '/assets/images/avatar_5.png',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: ['知识产权', '数字经济'],
|
||||||
|
bio: '专注数字经济与知识产权争议处理,擅长平台与内容合规。',
|
||||||
|
wechatQrImage: '/assets/qr/qr_5.png',
|
||||||
|
},
|
||||||
|
];
|
||||||
5
frontend_miniprogram/miniprogram/pages/firm/index.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"app-header": "/components/app-header/app-header"
|
||||||
|
}
|
||||||
|
}
|
||||||
182
frontend_miniprogram/miniprogram/pages/firm/index.less
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
.firm-page {
|
||||||
|
background: var(--bg-page);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-section {
|
||||||
|
position: relative;
|
||||||
|
height: 520rpx;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-bottom: 80rpx;
|
||||||
|
/* Space for overlap */
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* Updated gradient to match Burgundy Red */
|
||||||
|
background: linear-gradient(to bottom, rgba(142, 34, 48, 0.4), rgba(92, 13, 21, 0.9));
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 0 var(--spacing-lg);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 72rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-stats {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 14rpx 22rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
border: 1rpx solid rgba(255, 255, 255, 0.32);
|
||||||
|
background: linear-gradient(120deg, rgba(10, 21, 34, 0.62), rgba(19, 38, 56, 0.36));
|
||||||
|
box-shadow: 0 10rpx 28rpx rgba(7, 15, 27, 0.35), inset 0 1rpx 0 rgba(255, 255, 255, 0.24);
|
||||||
|
backdrop-filter: blur(10rpx);
|
||||||
|
-webkit-backdrop-filter: blur(10rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-num {
|
||||||
|
font-size: 44rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: rgba(242, 247, 252, 0.92);
|
||||||
|
margin-top: 4rpx;
|
||||||
|
text-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-divider {
|
||||||
|
width: 2rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.52), rgba(255, 255, 255, 0.12));
|
||||||
|
margin: 0 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
margin-top: -60rpx;
|
||||||
|
background: var(--bg-page);
|
||||||
|
border-radius: 32rpx 32rpx 0 0;
|
||||||
|
padding: var(--spacing-lg) var(--spacing-md);
|
||||||
|
min-height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
margin-bottom: var(--spacing-lg);
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: var(--shadow-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-label {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: var(--text-main);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-icon {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.8;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.area-tag {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--primary-color);
|
||||||
|
background: rgba(142, 34, 48, 0.08);
|
||||||
|
/* Primary color opacity */
|
||||||
|
padding: 10rpx 24rpx;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20rpx var(--spacing-md);
|
||||||
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||||||
|
z-index: 10;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-btn {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 8rpx 20rpx rgba(142, 34, 48, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
71
frontend_miniprogram/miniprogram/pages/firm/index.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { getFirmProfile } from '../../api/open';
|
||||||
|
import type { FirmInfo } from '../../types/card';
|
||||||
|
|
||||||
|
function createEmptyFirm(): FirmInfo {
|
||||||
|
return {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
logo: '',
|
||||||
|
intro: '',
|
||||||
|
hotlinePhone: '',
|
||||||
|
hqAddress: '',
|
||||||
|
hqLatitude: 0,
|
||||||
|
hqLongitude: 0,
|
||||||
|
officeCount: 0,
|
||||||
|
lawyerCount: 0,
|
||||||
|
heroImage: '',
|
||||||
|
officeList: [],
|
||||||
|
practiceAreas: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
firm: createEmptyFirm(),
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.loadFirmProfile();
|
||||||
|
},
|
||||||
|
async loadFirmProfile() {
|
||||||
|
this.setData({ loading: true });
|
||||||
|
try {
|
||||||
|
const firm = await getFirmProfile();
|
||||||
|
this.setData({ firm });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : '加载事务所信息失败';
|
||||||
|
wx.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goLawyerList() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '/pages/lawyer-list/index',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openLocation() {
|
||||||
|
const { firm } = this.data;
|
||||||
|
if (!firm.hqLatitude || !firm.hqLongitude) {
|
||||||
|
wx.showToast({
|
||||||
|
title: '暂未配置地图位置',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.openLocation({
|
||||||
|
latitude: firm.hqLatitude,
|
||||||
|
longitude: firm.hqLongitude,
|
||||||
|
name: firm.name,
|
||||||
|
address: firm.hqAddress,
|
||||||
|
scale: 18,
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '打开地图失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
60
frontend_miniprogram/miniprogram/pages/firm/index.wxml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<view class="container-page firm-page">
|
||||||
|
<!-- Custom Navigation Bar with transparent background initially if possible, or just standard -->
|
||||||
|
<app-header title="{{firm.name}}" back="{{false}}" background="rgba(255,255,255,0.9)"></app-header>
|
||||||
|
|
||||||
|
<scroll-view class="page-content" scroll-y="true" type="list">
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<view class="hero-section">
|
||||||
|
<image wx:if="{{firm.heroImage}}" class="hero-bg" mode="aspectFill" src="{{firm.heroImage}}"></image>
|
||||||
|
<view wx:if="{{!firm.heroImage}}" class="hero-overlay"></view>
|
||||||
|
<view class="hero-content">
|
||||||
|
<view class="firm-stats">
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-num">{{firm.officeCount}}</text>
|
||||||
|
<text class="stat-label">办公机构</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-divider"></view>
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-num">{{firm.lawyerCount}}</text>
|
||||||
|
<text class="stat-label">专业律师</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Content Container (Overlapping) -->
|
||||||
|
<view class="content-container">
|
||||||
|
|
||||||
|
<!-- Address Card -->
|
||||||
|
<view class="card address-card" bindtap="openLocation">
|
||||||
|
<view class="address-info">
|
||||||
|
<text class="address-label">总部地址</text>
|
||||||
|
<text class="address-text">{{firm.hqAddress}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="address-icon">></text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Intro Section -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section-title">律所简介</view>
|
||||||
|
<text class="intro-text">{{firm.intro}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Practice Areas -->
|
||||||
|
<view class="section">
|
||||||
|
<view class="section-title">专业领域</view>
|
||||||
|
<view class="tags-wrapper">
|
||||||
|
<view class="area-tag" wx:for="{{firm.practiceAreas}}" wx:key="*this">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="safe-area-bottom" style="height: 120rpx;"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- Bottom CTA -->
|
||||||
|
<view class="bottom-bar safe-area-bottom">
|
||||||
|
<button class="cta-btn" bindtap="goLawyerList">查找专业律师</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"app-header": "/components/app-header/app-header",
|
||||||
|
"lawyer-card": "/components/lawyer-card/lawyer-card",
|
||||||
|
"empty-state": "/components/empty-state/empty-state"
|
||||||
|
}
|
||||||
|
}
|
||||||
39
frontend_miniprogram/miniprogram/pages/history/index.less
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
.history-page {
|
||||||
|
background: var(--theme-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
padding: 14rpx 24rpx 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
margin: 0;
|
||||||
|
width: 156rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
line-height: 60rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
border: 1rpx solid var(--theme-border);
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--theme-primary);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-list {
|
||||||
|
padding: 16rpx 24rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-time {
|
||||||
|
margin: 10rpx 10rpx 0;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8e96a6;
|
||||||
|
}
|
||||||
80
frontend_miniprogram/miniprogram/pages/history/index.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { clearCardViewHistory, getCardViewHistory } from '../../utils/history';
|
||||||
|
import { formatTime } from '../../utils/util';
|
||||||
|
import type { Lawyer } from '../../types/card';
|
||||||
|
|
||||||
|
interface HistoryCardItem {
|
||||||
|
lawyer: Lawyer;
|
||||||
|
viewedAt: number;
|
||||||
|
timeText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFallbackLawyer(lawyerId: string): Lawyer {
|
||||||
|
return {
|
||||||
|
id: lawyerId,
|
||||||
|
name: '历史浏览名片',
|
||||||
|
title: '',
|
||||||
|
office: '',
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
address: '',
|
||||||
|
avatar: '',
|
||||||
|
coverImage: '',
|
||||||
|
specialties: [],
|
||||||
|
bio: '',
|
||||||
|
wechatQrImage: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
items: [] as HistoryCardItem[],
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
this.loadHistory();
|
||||||
|
},
|
||||||
|
|
||||||
|
loadHistory() {
|
||||||
|
const history = getCardViewHistory();
|
||||||
|
if (!history.length) {
|
||||||
|
this.setData({ items: [] });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = history
|
||||||
|
.map((record) => ({
|
||||||
|
lawyer: record.lawyer || createFallbackLawyer(record.lawyerId),
|
||||||
|
viewedAt: record.viewedAt,
|
||||||
|
timeText: formatTime(new Date(record.viewedAt)),
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.setData({ items });
|
||||||
|
},
|
||||||
|
|
||||||
|
handleLawyerSelect(event: WechatMiniprogram.CustomEvent<{ id: string }>) {
|
||||||
|
const lawyerId = event.detail.id;
|
||||||
|
if (!lawyerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/lawyer-detail/index?id=${lawyerId}`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clearHistory() {
|
||||||
|
if (!this.data.items.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.showModal({
|
||||||
|
title: '清空记录',
|
||||||
|
content: '确定清空所有名片查看记录吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
clearCardViewHistory();
|
||||||
|
this.setData({ items: [] });
|
||||||
|
wx.showToast({ title: '已清空', icon: 'success' });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
22
frontend_miniprogram/miniprogram/pages/history/index.wxml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<view class="container-page history-page">
|
||||||
|
<app-header title="名片查看记录" back="{{true}}" background="#f6f7fa"></app-header>
|
||||||
|
|
||||||
|
<scroll-view class="page-content" scroll-y="true" type="list">
|
||||||
|
<block wx:if="{{items.length}}">
|
||||||
|
<view class="actions">
|
||||||
|
<button class="clear-btn" bindtap="clearHistory">清空记录</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="history-list">
|
||||||
|
<view class="history-item" wx:for="{{items}}" wx:key="viewedAt" wx:for-item="item">
|
||||||
|
<lawyer-card lawyer="{{item.lawyer}}" bind:select="handleLawyerSelect"></lawyer-card>
|
||||||
|
<text class="history-time">查看时间:{{item.timeText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<block wx:else>
|
||||||
|
<empty-state text="还没有名片浏览记录"></empty-state>
|
||||||
|
</block>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
5
frontend_miniprogram/miniprogram/pages/index/index.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"navigation-bar": "/components/navigation-bar/navigation-bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
61
frontend_miniprogram/miniprogram/pages/index/index.less
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/**index.less**/
|
||||||
|
page {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.scrollarea {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userinfo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #aaa;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userinfo-avatar {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 128rpx;
|
||||||
|
height: 128rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usermotto {
|
||||||
|
margin-top: 200px;
|
||||||
|
}
|
||||||
|
.avatar-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
width: 56px !important;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
display: block;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname-wrapper {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-top: .5px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-bottom: .5px solid rgba(0, 0, 0, 0.1);
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname-label {
|
||||||
|
width: 105px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
54
frontend_miniprogram/miniprogram/pages/index/index.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// index.ts
|
||||||
|
// 获取应用实例
|
||||||
|
const app = getApp<IAppOption>()
|
||||||
|
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
||||||
|
|
||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
motto: 'Hello World',
|
||||||
|
userInfo: {
|
||||||
|
avatarUrl: defaultAvatarUrl,
|
||||||
|
nickName: '',
|
||||||
|
},
|
||||||
|
hasUserInfo: false,
|
||||||
|
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
|
||||||
|
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 事件处理函数
|
||||||
|
bindViewTap() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '../logs/logs',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onChooseAvatar(e: any) {
|
||||||
|
const { avatarUrl } = e.detail
|
||||||
|
const { nickName } = this.data.userInfo
|
||||||
|
this.setData({
|
||||||
|
"userInfo.avatarUrl": avatarUrl,
|
||||||
|
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onInputChange(e: any) {
|
||||||
|
const nickName = e.detail.value
|
||||||
|
const { avatarUrl } = this.data.userInfo
|
||||||
|
this.setData({
|
||||||
|
"userInfo.nickName": nickName,
|
||||||
|
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getUserProfile() {
|
||||||
|
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
|
||||||
|
wx.getUserProfile({
|
||||||
|
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
||||||
|
success: (res) => {
|
||||||
|
console.log(res)
|
||||||
|
this.setData({
|
||||||
|
userInfo: res.userInfo,
|
||||||
|
hasUserInfo: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
28
frontend_miniprogram/miniprogram/pages/index/index.wxml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!--index.wxml-->
|
||||||
|
<navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar>
|
||||||
|
<scroll-view class="scrollarea" scroll-y type="list">
|
||||||
|
<view class="container">
|
||||||
|
<view class="userinfo">
|
||||||
|
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
|
||||||
|
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
|
||||||
|
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
|
||||||
|
</button>
|
||||||
|
<view class="nickname-wrapper">
|
||||||
|
<text class="nickname-label">昵称</text>
|
||||||
|
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<block wx:elif="{{!hasUserInfo}}">
|
||||||
|
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
|
||||||
|
<view wx:else> 请使用2.10.4及以上版本基础库 </view>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
|
||||||
|
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="usermotto">
|
||||||
|
<text class="user-motto">{{motto}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"enableShareAppMessage": true,
|
||||||
|
"usingComponents": {
|
||||||
|
"app-header": "/components/app-header/app-header",
|
||||||
|
"action-dock": "/components/action-dock/action-dock",
|
||||||
|
"empty-state": "/components/empty-state/empty-state"
|
||||||
|
}
|
||||||
|
}
|
||||||
245
frontend_miniprogram/miniprogram/pages/lawyer-detail/index.less
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
.detail-page {
|
||||||
|
background: var(--bg-page);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-bg {
|
||||||
|
height: 300rpx;
|
||||||
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
border-radius: 0 0 40rpx 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
margin: 160rpx var(--spacing-md) 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--border-radius-lg);
|
||||||
|
padding: var(--spacing-lg);
|
||||||
|
box-shadow: var(--shadow-base);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 140rpx;
|
||||||
|
height: 140rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4rpx solid #fff;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
margin-top: -60rpx;
|
||||||
|
/* Overlap effect */
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: var(--spacing-md);
|
||||||
|
padding-top: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--primary-color);
|
||||||
|
background: rgba(142, 34, 48, 0.08);
|
||||||
|
/* Primary opacity */
|
||||||
|
padding: 2rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-name {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-btn {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-icon-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-btn text {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-body {
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
position: relative;
|
||||||
|
padding-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 6rpx;
|
||||||
|
bottom: 6rpx;
|
||||||
|
width: 6rpx;
|
||||||
|
background: var(--accent-color);
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-label {
|
||||||
|
width: 80rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-value {
|
||||||
|
flex: 1;
|
||||||
|
color: var(--text-main);
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-icon {
|
||||||
|
width: 60rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 1rpx;
|
||||||
|
background: var(--bg-page);
|
||||||
|
margin: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--primary-color);
|
||||||
|
background: rgba(142, 34, 48, 0.05);
|
||||||
|
padding: 8rpx 20rpx;
|
||||||
|
border-radius: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bio-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: justify;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bio-scroll {
|
||||||
|
height: 360rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-mini-card {
|
||||||
|
background: #fff;
|
||||||
|
padding: var(--spacing-md);
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-logo-mini-placeholder {
|
||||||
|
height: 60rpx;
|
||||||
|
width: 140rpx;
|
||||||
|
background: var(--bg-surface);
|
||||||
|
border-radius: 8rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-logo-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-family: serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-mini-info {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-mini-name {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--text-main);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firm-mini-address {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
color: var(--text-placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-bottom-space {
|
||||||
|
height: 160rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.not-found-action {
|
||||||
|
padding: var(--spacing-lg);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
background: var(--primary-color);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
}
|
||||||
188
frontend_miniprogram/miniprogram/pages/lawyer-detail/index.ts
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
import { getLawyerDetail, recordCardShare } from '../../api/open';
|
||||||
|
import type { FirmInfo } from '../../types/card';
|
||||||
|
import type { Lawyer } from '../../types/card';
|
||||||
|
import { appendCardViewRecord } from '../../utils/history';
|
||||||
|
|
||||||
|
function createEmptyFirm(): FirmInfo {
|
||||||
|
return {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
logo: '',
|
||||||
|
intro: '',
|
||||||
|
hotlinePhone: '',
|
||||||
|
hqAddress: '',
|
||||||
|
hqLatitude: 0,
|
||||||
|
hqLongitude: 0,
|
||||||
|
officeCount: 0,
|
||||||
|
lawyerCount: 0,
|
||||||
|
heroImage: '',
|
||||||
|
officeList: [],
|
||||||
|
practiceAreas: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDetailBgStyle(coverImage?: string): string {
|
||||||
|
const cover = typeof coverImage === 'string' ? coverImage.trim() : '';
|
||||||
|
if (!cover) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return `background-image: url("${cover}"); background-size: cover; background-position: center;`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUseBioScroll(bio?: string): boolean {
|
||||||
|
const text = typeof bio === 'string' ? bio.trim() : '';
|
||||||
|
return text.length > 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
firm: createEmptyFirm(),
|
||||||
|
lawyer: null as Lawyer | null,
|
||||||
|
notFound: false,
|
||||||
|
specialtiesText: '',
|
||||||
|
detailBgStyle: '',
|
||||||
|
bioScrollable: false,
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
async onLoad(options: Record<string, string | undefined>) {
|
||||||
|
const lawyerId = typeof options.id === 'string' ? options.id : '';
|
||||||
|
const sourceType = typeof options.sourceType === 'string' ? options.sourceType : 'DIRECT';
|
||||||
|
const shareFromCardId = typeof options.shareFromCardId === 'string' ? options.shareFromCardId : '';
|
||||||
|
|
||||||
|
if (!lawyerId) {
|
||||||
|
this.setData({ notFound: true, specialtiesText: '', detailBgStyle: '', bioScrollable: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setData({ loading: true });
|
||||||
|
try {
|
||||||
|
const payload = await getLawyerDetail(lawyerId, sourceType, shareFromCardId);
|
||||||
|
this.setData({
|
||||||
|
firm: payload.firm,
|
||||||
|
lawyer: payload.lawyer,
|
||||||
|
notFound: false,
|
||||||
|
specialtiesText: payload.lawyer.specialties.join(';'),
|
||||||
|
detailBgStyle: buildDetailBgStyle(payload.lawyer.coverImage),
|
||||||
|
bioScrollable: shouldUseBioScroll(payload.lawyer.bio),
|
||||||
|
});
|
||||||
|
appendCardViewRecord(payload.lawyer);
|
||||||
|
wx.showShareMenu({ menus: ['shareAppMessage'] });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : '律师信息不存在';
|
||||||
|
this.setData({ notFound: true, specialtiesText: '', detailBgStyle: '', bioScrollable: false });
|
||||||
|
wx.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDockAction(event: WechatMiniprogram.CustomEvent<{ action: string }>) {
|
||||||
|
const action = event.detail.action;
|
||||||
|
switch (action) {
|
||||||
|
case 'save':
|
||||||
|
this.saveContact();
|
||||||
|
break;
|
||||||
|
case 'location':
|
||||||
|
this.navigateOffice();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
saveContact() {
|
||||||
|
const lawyer = this.data.lawyer;
|
||||||
|
if (!lawyer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.addPhoneContact({
|
||||||
|
firstName: lawyer.name,
|
||||||
|
mobilePhoneNumber: lawyer.phone,
|
||||||
|
email: lawyer.email,
|
||||||
|
organization: this.data.firm.name,
|
||||||
|
title: lawyer.title,
|
||||||
|
workAddressStreet: lawyer.address,
|
||||||
|
remark: lawyer.specialties.join('、'),
|
||||||
|
success: () => {
|
||||||
|
wx.showToast({ title: '已添加到通讯录', icon: 'success' });
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '添加失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
callPhone() {
|
||||||
|
const phone = this.data.lawyer ? this.data.lawyer.phone : '';
|
||||||
|
if (!phone) {
|
||||||
|
wx.showToast({ title: '暂无联系电话', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.makePhoneCall({
|
||||||
|
phoneNumber: phone,
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '拨号失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
navigateOffice() {
|
||||||
|
if (!this.data.firm.hqLatitude || !this.data.firm.hqLongitude) {
|
||||||
|
wx.showToast({ title: '暂未配置地图位置', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.openLocation({
|
||||||
|
latitude: this.data.firm.hqLatitude,
|
||||||
|
longitude: this.data.firm.hqLongitude,
|
||||||
|
name: this.data.firm.name,
|
||||||
|
address: this.data.firm.hqAddress,
|
||||||
|
scale: 18,
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '打开地图失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
previewWechatQr() {
|
||||||
|
const url = this.data.lawyer ? this.data.lawyer.wechatQrImage : '';
|
||||||
|
if (!url) {
|
||||||
|
wx.showToast({ title: '二维码未配置', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.previewImage({
|
||||||
|
current: url,
|
||||||
|
urls: [url],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
goLawyerList() {
|
||||||
|
wx.navigateTo({ url: '/pages/lawyer-list/index' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onShareAppMessage() {
|
||||||
|
const lawyer = this.data.lawyer;
|
||||||
|
if (!lawyer) {
|
||||||
|
return {
|
||||||
|
title: `${this.data.firm.name || '电子名片'}电子名片`,
|
||||||
|
path: '/pages/firm/index',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharePath = `/pages/lawyer-detail/index?id=${lawyer.id}&sourceType=SHARE&shareFromCardId=${lawyer.id}`;
|
||||||
|
recordCardShare(lawyer.id, sharePath).catch(() => {
|
||||||
|
// 分享埋点失败不阻断分享动作
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: `${lawyer.name}律师电子名片`,
|
||||||
|
path: sharePath,
|
||||||
|
imageUrl: lawyer.avatar,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<view class="container-page detail-page">
|
||||||
|
<app-header title="名片详情" back="{{true}}" background="transparent"></app-header>
|
||||||
|
|
||||||
|
<block wx:if="{{notFound}}">
|
||||||
|
<view class="page-content">
|
||||||
|
<empty-state text="未找到律师信息"></empty-state>
|
||||||
|
<view class="not-found-action">
|
||||||
|
<button class="back-btn" bindtap="goLawyerList">返回律师列表</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<block wx:else>
|
||||||
|
<scroll-view class="page-content" scroll-y="true" type="list">
|
||||||
|
<!-- Top Background -->
|
||||||
|
<view class="detail-bg" style="{{detailBgStyle}}"></view>
|
||||||
|
|
||||||
|
<!-- Profile Card (Overlapping) -->
|
||||||
|
<view class="profile-card">
|
||||||
|
<image class="avatar" src="{{lawyer.avatar}}" mode="aspectFill"></image>
|
||||||
|
<view class="profile-info">
|
||||||
|
<view class="name-row">
|
||||||
|
<text class="name">{{lawyer.name}}</text>
|
||||||
|
<text class="title">{{lawyer.title}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="firm-name">{{firm.name}} | {{lawyer.office}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="qr-btn" bindtap="previewWechatQr">
|
||||||
|
<!-- Replaced icon with text for simplicity if icon missing -->
|
||||||
|
<text class="qr-icon-text">⚲</text>
|
||||||
|
<text>二维码</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Content Sections -->
|
||||||
|
<view class="content-body">
|
||||||
|
|
||||||
|
<!-- Contact Section -->
|
||||||
|
<view class="section-card">
|
||||||
|
<view class="section-header">联系方式</view>
|
||||||
|
<view class="contact-item" bindtap="callPhone">
|
||||||
|
<text class="contact-label">电话</text>
|
||||||
|
<text class="contact-value">{{lawyer.phone}}</text>
|
||||||
|
<view class="action-icon phone">📞</view>
|
||||||
|
</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
<view class="contact-item">
|
||||||
|
<text class="contact-label">邮箱</text>
|
||||||
|
<text class="contact-value">{{lawyer.email}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Practise Areas -->
|
||||||
|
<view class="section-card">
|
||||||
|
<view class="section-header">执业领域</view>
|
||||||
|
<view class="tags-row">
|
||||||
|
<text class="tag" wx:for="{{lawyer.specialties}}" wx:key="*this">{{item}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- Bio -->
|
||||||
|
<view class="section-card">
|
||||||
|
<view class="section-header">个人简介</view>
|
||||||
|
<scroll-view wx:if="{{bioScrollable}}" class="bio-scroll" scroll-y="true" show-scrollbar="true">
|
||||||
|
<view class="bio-text">{{lawyer.bio}}</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view wx:else class="bio-text">{{lawyer.bio}}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<view class="detail-bottom-space"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- Fixed Action Dock -->
|
||||||
|
<action-dock bind:action="handleDockAction"></action-dock>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"app-header": "/components/app-header/app-header",
|
||||||
|
"lawyer-card": "/components/lawyer-card/lawyer-card",
|
||||||
|
"filter-bar": "/components/filter-bar/filter-bar",
|
||||||
|
"empty-state": "/components/empty-state/empty-state"
|
||||||
|
}
|
||||||
|
}
|
||||||
116
frontend_miniprogram/miniprogram/pages/lawyer-list/index.less
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
.lawyer-list-page {
|
||||||
|
background: var(--bg-page);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: var(--bg-page);
|
||||||
|
padding-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrap {
|
||||||
|
padding: var(--spacing-sm) var(--spacing-md);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
background: var(--bg-surface);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
gap: 12rpx;
|
||||||
|
border: 1rpx solid transparent;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box:active {
|
||||||
|
background: #fff;
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: var(--text-main);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-placeholder {
|
||||||
|
color: var(--text-placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacing-md);
|
||||||
|
padding: 0 var(--spacing-md) var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hotline-btn {
|
||||||
|
background: rgba(142, 34, 48, 0.06);
|
||||||
|
/* Burgundy tint */
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-btn {
|
||||||
|
background: #fff;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1rpx solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-wrap {
|
||||||
|
padding: 0 var(--spacing-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-item {
|
||||||
|
margin-bottom: var(--spacing-md);
|
||||||
|
background: #fff;
|
||||||
|
/* Ensure card background is white */
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-bottom-space {
|
||||||
|
height: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* History Floating Action Button styling */
|
||||||
|
.history-fab {
|
||||||
|
position: fixed;
|
||||||
|
right: var(--spacing-md);
|
||||||
|
bottom: calc(var(--spacing-lg) + env(safe-area-inset-bottom));
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
padding: 16rpx 32rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 20;
|
||||||
|
border: 1rpx solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: var(--text-main);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
147
frontend_miniprogram/miniprogram/pages/lawyer-list/index.ts
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import { getFirmProfile, listLawyers } from '../../api/open';
|
||||||
|
import type { Lawyer } from '../../types/card';
|
||||||
|
|
||||||
|
const ALL_OFFICES = '所有办公机构';
|
||||||
|
const ALL_AREAS = '全部专业领域';
|
||||||
|
|
||||||
|
let searchDebounceTimer: number | null = null;
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
firmName: '',
|
||||||
|
firmAddress: '',
|
||||||
|
firmLatitude: 0,
|
||||||
|
firmLongitude: 0,
|
||||||
|
keyword: '',
|
||||||
|
selectedOffice: ALL_OFFICES,
|
||||||
|
selectedArea: ALL_AREAS,
|
||||||
|
officeOptions: [ALL_OFFICES],
|
||||||
|
areaOptions: [ALL_AREAS],
|
||||||
|
filteredLawyers: [] as Lawyer[],
|
||||||
|
hotlinePhone: '',
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
this.initializePage();
|
||||||
|
},
|
||||||
|
|
||||||
|
async initializePage() {
|
||||||
|
this.setData({ loading: true });
|
||||||
|
try {
|
||||||
|
const firm = await getFirmProfile();
|
||||||
|
this.setData({
|
||||||
|
firmName: firm.name,
|
||||||
|
firmAddress: firm.hqAddress,
|
||||||
|
firmLatitude: firm.hqLatitude,
|
||||||
|
firmLongitude: firm.hqLongitude,
|
||||||
|
hotlinePhone: firm.hotlinePhone,
|
||||||
|
officeOptions: [ALL_OFFICES, ...firm.officeList],
|
||||||
|
areaOptions: [ALL_AREAS, ...firm.practiceAreas],
|
||||||
|
});
|
||||||
|
await this.loadLawyers();
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : '加载列表失败';
|
||||||
|
wx.showToast({ title: message, icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
if (searchDebounceTimer !== null) {
|
||||||
|
clearTimeout(searchDebounceTimer);
|
||||||
|
searchDebounceTimer = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSearchInput(event: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||||
|
const keyword = event.detail.value || '';
|
||||||
|
this.setData({ keyword });
|
||||||
|
|
||||||
|
if (searchDebounceTimer !== null) {
|
||||||
|
clearTimeout(searchDebounceTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchDebounceTimer = setTimeout(() => {
|
||||||
|
this.loadLawyers();
|
||||||
|
}, 250) as unknown as number;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOfficeChange(event: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||||
|
this.setData({ selectedOffice: event.detail.value });
|
||||||
|
this.loadLawyers();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAreaChange(event: WechatMiniprogram.CustomEvent<{ value: string }>) {
|
||||||
|
this.setData({ selectedArea: event.detail.value });
|
||||||
|
this.loadLawyers();
|
||||||
|
},
|
||||||
|
|
||||||
|
async loadLawyers() {
|
||||||
|
this.setData({ loading: true });
|
||||||
|
try {
|
||||||
|
const filteredLawyers = await listLawyers({
|
||||||
|
keyword: this.data.keyword.trim() || undefined,
|
||||||
|
office: this.data.selectedOffice === ALL_OFFICES ? undefined : this.data.selectedOffice,
|
||||||
|
practiceArea: this.data.selectedArea === ALL_AREAS ? undefined : this.data.selectedArea,
|
||||||
|
});
|
||||||
|
this.setData({ filteredLawyers });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : '加载律师列表失败';
|
||||||
|
wx.showToast({ title: message, icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleLawyerSelect(event: WechatMiniprogram.CustomEvent<{ id: string }>) {
|
||||||
|
const lawyerId = event.detail.id;
|
||||||
|
if (!lawyerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.navigateTo({
|
||||||
|
url: `/pages/lawyer-detail/index?id=${lawyerId}`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
callHotline() {
|
||||||
|
if (!this.data.hotlinePhone) {
|
||||||
|
wx.showToast({
|
||||||
|
title: '暂无联系电话',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.makePhoneCall({
|
||||||
|
phoneNumber: this.data.hotlinePhone,
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '拨号失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
openOffice() {
|
||||||
|
if (!this.data.firmLatitude || !this.data.firmLongitude) {
|
||||||
|
wx.showToast({ title: '暂未配置地图位置', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wx.openLocation({
|
||||||
|
latitude: this.data.firmLatitude,
|
||||||
|
longitude: this.data.firmLongitude,
|
||||||
|
name: this.data.firmName,
|
||||||
|
address: this.data.firmAddress,
|
||||||
|
scale: 18,
|
||||||
|
fail: () => {
|
||||||
|
wx.showToast({ title: '打开地图失败', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
goHistory() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '/pages/history/index',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<view class="container-page lawyer-list-page">
|
||||||
|
<app-header title="专业律师" back="{{true}}" background="#fff"></app-header>
|
||||||
|
|
||||||
|
<!-- Sticky Header Wrapper -->
|
||||||
|
<view class="sticky-header">
|
||||||
|
<view class="search-wrap">
|
||||||
|
<view class="search-box">
|
||||||
|
<icon type="search" size="16" color="#999"></icon>
|
||||||
|
<input
|
||||||
|
class="search-input"
|
||||||
|
placeholder-class="search-placeholder"
|
||||||
|
placeholder="搜索律师姓名、专业领域..."
|
||||||
|
value="{{keyword}}"
|
||||||
|
bindinput="onSearchInput"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<filter-bar
|
||||||
|
office-options="{{officeOptions}}"
|
||||||
|
area-options="{{areaOptions}}"
|
||||||
|
selected-office="{{selectedOffice}}"
|
||||||
|
selected-area="{{selectedArea}}"
|
||||||
|
bind:officechange="handleOfficeChange"
|
||||||
|
bind:areachange="handleAreaChange"
|
||||||
|
></filter-bar>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="quick-actions">
|
||||||
|
<view class="action-btn hotline-btn" bindtap="callHotline">
|
||||||
|
<image class="action-icon" src="/assets/icons/phone.svg" mode="aspectFit" wx:if="{{false}}"></image> <!-- Placeholder for icon -->
|
||||||
|
<text>联系电话</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-btn map-btn" bindtap="openOffice">
|
||||||
|
<text>总部导航</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="page-content list-scroll" scroll-y="true" type="list">
|
||||||
|
<view class="list-wrap">
|
||||||
|
<block wx:if="{{filteredLawyers.length}}">
|
||||||
|
<view class="card-item" wx:for="{{filteredLawyers}}" wx:key="id" wx:for-item="item">
|
||||||
|
<lawyer-card lawyer="{{item}}" bind:select="handleLawyerSelect"></lawyer-card>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<empty-state text="未找到匹配的律师"></empty-state>
|
||||||
|
</block>
|
||||||
|
<view class="list-bottom-space"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="history-fab" bindtap="goHistory">
|
||||||
|
<text class="history-text">浏览记录</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
5
frontend_miniprogram/miniprogram/pages/logs/logs.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"navigation-bar": "/components/navigation-bar/navigation-bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
frontend_miniprogram/miniprogram/pages/logs/logs.less
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
page {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.scrollarea {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
.log-item {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.log-item:last-child {
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
21
frontend_miniprogram/miniprogram/pages/logs/logs.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// logs.ts
|
||||||
|
// const util = require('../../utils/util.js')
|
||||||
|
import { formatTime } from '../../utils/util'
|
||||||
|
|
||||||
|
Component({
|
||||||
|
data: {
|
||||||
|
logs: [],
|
||||||
|
},
|
||||||
|
lifetimes: {
|
||||||
|
attached() {
|
||||||
|
this.setData({
|
||||||
|
logs: (wx.getStorageSync('logs') || []).map((log: string) => {
|
||||||
|
return {
|
||||||
|
date: formatTime(new Date(log)),
|
||||||
|
timeStamp: log
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
7
frontend_miniprogram/miniprogram/pages/logs/logs.wxml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!--logs.wxml-->
|
||||||
|
<navigation-bar title="查看启动日志" back="{{true}}" color="black" background="#FFF"></navigation-bar>
|
||||||
|
<scroll-view class="scrollarea" scroll-y type="list">
|
||||||
|
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
|
||||||
|
<view class="log-item">{{index + 1}}. {{log.date}}</view>
|
||||||
|
</block>
|
||||||
|
</scroll-view>
|
||||||
7
frontend_miniprogram/miniprogram/sitemap.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
|
||||||
|
"rules": [{
|
||||||
|
"action": "allow",
|
||||||
|
"page": "*"
|
||||||
|
}]
|
||||||
|
}
|
||||||
36
frontend_miniprogram/miniprogram/types/card.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
export interface FirmInfo {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
logo: string;
|
||||||
|
intro: string;
|
||||||
|
hotlinePhone: string;
|
||||||
|
hqAddress: string;
|
||||||
|
hqLatitude: number;
|
||||||
|
hqLongitude: number;
|
||||||
|
officeCount: number;
|
||||||
|
lawyerCount: number;
|
||||||
|
heroImage: string;
|
||||||
|
officeList: string[];
|
||||||
|
practiceAreas: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Lawyer {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
office: string;
|
||||||
|
phone: string;
|
||||||
|
email: string;
|
||||||
|
address: string;
|
||||||
|
avatar: string;
|
||||||
|
coverImage: string;
|
||||||
|
specialties: string[];
|
||||||
|
bio: string;
|
||||||
|
wechatQrImage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CardViewRecord {
|
||||||
|
lawyerId: string;
|
||||||
|
viewedAt: number;
|
||||||
|
lawyer?: Lawyer;
|
||||||
|
}
|
||||||
65
frontend_miniprogram/miniprogram/utils/history.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { CARD_VIEW_HISTORY_KEY } from '../constants/storage';
|
||||||
|
import type { CardViewRecord, Lawyer } from '../types/card';
|
||||||
|
|
||||||
|
function normalizeLawyerSnapshot(input: unknown): Lawyer | undefined {
|
||||||
|
if (!input || typeof input !== 'object') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lawyer = input as Partial<Lawyer>;
|
||||||
|
if (typeof lawyer.id !== 'string' || !lawyer.id) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: lawyer.id,
|
||||||
|
name: typeof lawyer.name === 'string' ? lawyer.name : '',
|
||||||
|
title: typeof lawyer.title === 'string' ? lawyer.title : '',
|
||||||
|
office: typeof lawyer.office === 'string' ? lawyer.office : '',
|
||||||
|
phone: typeof lawyer.phone === 'string' ? lawyer.phone : '',
|
||||||
|
email: typeof lawyer.email === 'string' ? lawyer.email : '',
|
||||||
|
address: typeof lawyer.address === 'string' ? lawyer.address : '',
|
||||||
|
avatar: typeof lawyer.avatar === 'string' ? lawyer.avatar : '',
|
||||||
|
coverImage: typeof lawyer.coverImage === 'string' ? lawyer.coverImage : '',
|
||||||
|
specialties: Array.isArray(lawyer.specialties)
|
||||||
|
? lawyer.specialties.filter((item): item is string => typeof item === 'string')
|
||||||
|
: [],
|
||||||
|
bio: typeof lawyer.bio === 'string' ? lawyer.bio : '',
|
||||||
|
wechatQrImage: typeof lawyer.wechatQrImage === 'string' ? lawyer.wechatQrImage : '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCardViewHistory(): CardViewRecord[] {
|
||||||
|
const raw = wx.getStorageSync(CARD_VIEW_HISTORY_KEY);
|
||||||
|
if (!Array.isArray(raw)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return raw
|
||||||
|
.map((item) => {
|
||||||
|
const record = item as { lawyerId?: unknown; viewedAt?: unknown; lawyer?: unknown };
|
||||||
|
const lawyerId = typeof record.lawyerId === 'string' ? record.lawyerId : '';
|
||||||
|
const viewedAt = typeof record.viewedAt === 'number' ? record.viewedAt : 0;
|
||||||
|
const lawyer = normalizeLawyerSnapshot(record.lawyer);
|
||||||
|
return { lawyerId, viewedAt, lawyer };
|
||||||
|
})
|
||||||
|
.filter((item) => Boolean(item.lawyerId) && item.viewedAt > 0)
|
||||||
|
.sort((a, b) => b.viewedAt - a.viewedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function appendCardViewRecord(lawyer: Lawyer): void {
|
||||||
|
if (!lawyer.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const current = getCardViewHistory().filter((item) => item.lawyerId !== lawyer.id);
|
||||||
|
current.unshift({
|
||||||
|
lawyerId: lawyer.id,
|
||||||
|
viewedAt: Date.now(),
|
||||||
|
lawyer,
|
||||||
|
});
|
||||||
|
wx.setStorageSync(CARD_VIEW_HISTORY_KEY, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearCardViewHistory(): void {
|
||||||
|
wx.removeStorageSync(CARD_VIEW_HISTORY_KEY);
|
||||||
|
}
|
||||||
75
frontend_miniprogram/miniprogram/utils/http.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { API_BASE_URL_OVERRIDE_KEY, tenantRuntimeConfig } from '../config/runtime';
|
||||||
|
import { getMiniappAppId, getMiniappEnvVersion } from './miniapp';
|
||||||
|
|
||||||
|
interface ApiResponse<T> {
|
||||||
|
code: string;
|
||||||
|
message: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequestOptions {
|
||||||
|
url: string;
|
||||||
|
method?: 'GET' | 'POST';
|
||||||
|
data?: WechatMiniprogram.IAnyObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBaseUrl(baseUrl: string): string {
|
||||||
|
return baseUrl.trim().replace(/\/+$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getApiBaseUrl(): string {
|
||||||
|
const override = wx.getStorageSync(API_BASE_URL_OVERRIDE_KEY);
|
||||||
|
if (typeof override === 'string' && override.trim()) {
|
||||||
|
return normalizeBaseUrl(override);
|
||||||
|
}
|
||||||
|
|
||||||
|
const envVersion = getMiniappEnvVersion();
|
||||||
|
const baseUrl = tenantRuntimeConfig.apiBaseUrlByEnv[envVersion];
|
||||||
|
if (!baseUrl || !baseUrl.trim()) {
|
||||||
|
throw new Error(`未配置 ${envVersion} 环境的接口域名`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
||||||
|
if (envVersion !== 'develop' && !normalizedBaseUrl.startsWith('https://')) {
|
||||||
|
throw new Error(`${envVersion} 环境接口域名必须使用 HTTPS`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedBaseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function request<T>(options: RequestOptions): Promise<T> {
|
||||||
|
const appId = getMiniappAppId();
|
||||||
|
if (!appId) {
|
||||||
|
return Promise.reject(new Error('未获取到小程序 AppID'));
|
||||||
|
}
|
||||||
|
|
||||||
|
let apiBaseUrl = '';
|
||||||
|
try {
|
||||||
|
apiBaseUrl = getApiBaseUrl();
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error instanceof Error ? error : new Error('接口域名配置无效'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
wx.request({
|
||||||
|
url: `${apiBaseUrl}${options.url}`,
|
||||||
|
method: options.method || 'GET',
|
||||||
|
data: options.data,
|
||||||
|
header: {
|
||||||
|
'X-Miniapp-Appid': appId,
|
||||||
|
},
|
||||||
|
success: (response) => {
|
||||||
|
const payload = response.data as ApiResponse<T> | undefined;
|
||||||
|
if (response.statusCode >= 200 && response.statusCode < 300 && payload && payload.code === '0') {
|
||||||
|
resolve(payload.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = payload && payload.message ? payload.message : '请求失败';
|
||||||
|
reject(new Error(message));
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
reject(new Error('网络异常,请稍后重试'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
29
frontend_miniprogram/miniprogram/utils/miniapp.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import type { MiniProgramEnvVersion } from '../config/runtime';
|
||||||
|
|
||||||
|
const APPID_OVERRIDE_KEY = 'miniapp_appid_override';
|
||||||
|
|
||||||
|
export function getMiniappAppId(): string {
|
||||||
|
const override = wx.getStorageSync(APPID_OVERRIDE_KEY);
|
||||||
|
if (typeof override === 'string' && override.trim()) {
|
||||||
|
return override.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const accountInfo = wx.getAccountInfoSync();
|
||||||
|
return accountInfo.miniProgram.appId || '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMiniappEnvVersion(): MiniProgramEnvVersion {
|
||||||
|
try {
|
||||||
|
const envVersion = wx.getAccountInfoSync().miniProgram.envVersion;
|
||||||
|
if (envVersion === 'trial' || envVersion === 'release') {
|
||||||
|
return envVersion;
|
||||||
|
}
|
||||||
|
return 'develop';
|
||||||
|
} catch {
|
||||||
|
return 'develop';
|
||||||
|
}
|
||||||
|
}
|
||||||
19
frontend_miniprogram/miniprogram/utils/util.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export const formatTime = (date: Date) => {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
|
||||||
|
return (
|
||||||
|
[year, month, day].map(formatNumber).join('/') +
|
||||||
|
' ' +
|
||||||
|
[hour, minute, second].map(formatNumber).join(':')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatNumber = (n: number) => {
|
||||||
|
const s = n.toString()
|
||||||
|
return s[1] ? s : '0' + s
|
||||||
|
}
|
||||||
15
frontend_miniprogram/package.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "miniprogram-ts-less-quickstart",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"scripts": {
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "",
|
||||||
|
"dependencies": {
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"miniprogram-api-typings": "^2.8.3-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
51
frontend_miniprogram/project.config.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"description": "项目配置文件",
|
||||||
|
"miniprogramRoot": "miniprogram/",
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"setting": {
|
||||||
|
"useCompilerPlugins": [
|
||||||
|
"typescript",
|
||||||
|
"less"
|
||||||
|
],
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
},
|
||||||
|
"coverView": false,
|
||||||
|
"postcss": false,
|
||||||
|
"minified": false,
|
||||||
|
"enhance": false,
|
||||||
|
"showShadowRootInWxmlPanel": false,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"ignoreUploadUnusedFiles": true,
|
||||||
|
"compileHotReLoad": false,
|
||||||
|
"skylineRenderEnable": true,
|
||||||
|
"es6": false,
|
||||||
|
"compileWorklet": false,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"uploadWithSourceMap": true,
|
||||||
|
"packNpmManually": false,
|
||||||
|
"minifyWXSS": true,
|
||||||
|
"minifyWXML": true,
|
||||||
|
"localPlugins": false,
|
||||||
|
"condition": false,
|
||||||
|
"swc": false,
|
||||||
|
"disableSWC": true,
|
||||||
|
"disableUseStrict": false
|
||||||
|
},
|
||||||
|
"simulatorType": "wechat",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"condition": {},
|
||||||
|
"srcMiniprogramRoot": "miniprogram/",
|
||||||
|
"editorSetting": {
|
||||||
|
"tabIndent": "insertSpaces",
|
||||||
|
"tabSize": 2
|
||||||
|
},
|
||||||
|
"libVersion": "2.32.3",
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"appid": "wx790fd3f9448f6e87"
|
||||||
|
}
|
||||||
30
frontend_miniprogram/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"module": "CommonJS",
|
||||||
|
"target": "ES2017",
|
||||||
|
"allowJs": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"strict": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
|
"lib": ["ES2017"],
|
||||||
|
"typeRoots": [
|
||||||
|
"./typings"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
8
frontend_miniprogram/typings/index.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/// <reference path="./types/index.d.ts" />
|
||||||
|
|
||||||
|
interface IAppOption {
|
||||||
|
globalData: {
|
||||||
|
userInfo?: WechatMiniprogram.UserInfo,
|
||||||
|
}
|
||||||
|
userInfoReadyCallback?: WechatMiniprogram.GetUserInfoSuccessCallback,
|
||||||
|
}
|
||||||
1
frontend_miniprogram/typings/types/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/// <reference path="./wx/index.d.ts" />
|
||||||
74
frontend_miniprogram/typings/types/wx/index.d.ts
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
/// <reference path="./lib.wx.app.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.page.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.api.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.cloud.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.component.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.behavior.d.ts" />
|
||||||
|
/// <reference path="./lib.wx.event.d.ts" />
|
||||||
|
|
||||||
|
declare namespace WechatMiniprogram {
|
||||||
|
type IAnyObject = Record<string, any>
|
||||||
|
type Optional<F> = F extends (arg: infer P) => infer R ? (arg?: P) => R : F
|
||||||
|
type OptionalInterface<T> = { [K in keyof T]: Optional<T[K]> }
|
||||||
|
interface AsyncMethodOptionLike {
|
||||||
|
success?: (...args: any[]) => void
|
||||||
|
}
|
||||||
|
type PromisifySuccessResult<
|
||||||
|
P,
|
||||||
|
T extends AsyncMethodOptionLike
|
||||||
|
> = P extends { success: any }
|
||||||
|
? void
|
||||||
|
: P extends { fail: any }
|
||||||
|
? void
|
||||||
|
: P extends { complete: any }
|
||||||
|
? void
|
||||||
|
: Promise<Parameters<Exclude<T['success'], undefined>>[0]>
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const console: WechatMiniprogram.Console
|
||||||
|
declare const wx: WechatMiniprogram.Wx
|
||||||
|
/** 引入模块。返回模块通过 `module.exports` 或 `exports` 暴露的接口。 */
|
||||||
|
declare function require(
|
||||||
|
/** 需要引入模块文件相对于当前文件的相对路径,或 npm 模块名,或 npm 模块路径。不支持绝对路径 */
|
||||||
|
module: string
|
||||||
|
): any
|
||||||
|
/** 引入插件。返回插件通过 `main` 暴露的接口。 */
|
||||||
|
declare function requirePlugin(
|
||||||
|
/** 需要引入的插件的 alias */
|
||||||
|
module: string
|
||||||
|
): any
|
||||||
|
/** 插件引入当前使用者小程序。返回使用者小程序通过 [插件配置中 `export` 暴露的接口](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/using.html#%E5%AF%BC%E5%87%BA%E5%88%B0%E6%8F%92%E4%BB%B6)。
|
||||||
|
*
|
||||||
|
* 该接口只在插件中存在
|
||||||
|
*
|
||||||
|
* 最低基础库: `2.11.1` */
|
||||||
|
declare function requireMiniProgram(): any
|
||||||
|
/** 当前模块对象 */
|
||||||
|
declare let module: {
|
||||||
|
/** 模块向外暴露的对象,使用 `require` 引用该模块时可以获取 */
|
||||||
|
exports: any
|
||||||
|
}
|
||||||
|
/** `module.exports` 的引用 */
|
||||||
|
declare let exports: any
|
||||||
19671
frontend_miniprogram/typings/types/wx/lib.wx.api.d.ts
vendored
Normal file
270
frontend_miniprogram/typings/types/wx/lib.wx.app.d.ts
vendored
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
declare namespace WechatMiniprogram.App {
|
||||||
|
interface ReferrerInfo {
|
||||||
|
/** 来源小程序或公众号或App的 appId
|
||||||
|
*
|
||||||
|
* 以下场景支持返回 referrerInfo.appId:
|
||||||
|
* - 1020(公众号 profile 页相关小程序列表): appId
|
||||||
|
* - 1035(公众号自定义菜单):来源公众号 appId
|
||||||
|
* - 1036(App 分享消息卡片):来源应用 appId
|
||||||
|
* - 1037(小程序打开小程序):来源小程序 appId
|
||||||
|
* - 1038(从另一个小程序返回):来源小程序 appId
|
||||||
|
* - 1043(公众号模板消息):来源公众号 appId
|
||||||
|
*/
|
||||||
|
appId: string
|
||||||
|
/** 来源小程序传过来的数据,scene=1037或1038时支持 */
|
||||||
|
extraData?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type SceneValues =
|
||||||
|
| 1001
|
||||||
|
| 1005
|
||||||
|
| 1006
|
||||||
|
| 1007
|
||||||
|
| 1008
|
||||||
|
| 1011
|
||||||
|
| 1012
|
||||||
|
| 1013
|
||||||
|
| 1014
|
||||||
|
| 1017
|
||||||
|
| 1019
|
||||||
|
| 1020
|
||||||
|
| 1023
|
||||||
|
| 1024
|
||||||
|
| 1025
|
||||||
|
| 1026
|
||||||
|
| 1027
|
||||||
|
| 1028
|
||||||
|
| 1029
|
||||||
|
| 1030
|
||||||
|
| 1031
|
||||||
|
| 1032
|
||||||
|
| 1034
|
||||||
|
| 1035
|
||||||
|
| 1036
|
||||||
|
| 1037
|
||||||
|
| 1038
|
||||||
|
| 1039
|
||||||
|
| 1042
|
||||||
|
| 1043
|
||||||
|
| 1044
|
||||||
|
| 1045
|
||||||
|
| 1046
|
||||||
|
| 1047
|
||||||
|
| 1048
|
||||||
|
| 1049
|
||||||
|
| 1052
|
||||||
|
| 1053
|
||||||
|
| 1056
|
||||||
|
| 1057
|
||||||
|
| 1058
|
||||||
|
| 1059
|
||||||
|
| 1064
|
||||||
|
| 1067
|
||||||
|
| 1069
|
||||||
|
| 1071
|
||||||
|
| 1072
|
||||||
|
| 1073
|
||||||
|
| 1074
|
||||||
|
| 1077
|
||||||
|
| 1078
|
||||||
|
| 1079
|
||||||
|
| 1081
|
||||||
|
| 1082
|
||||||
|
| 1084
|
||||||
|
| 1089
|
||||||
|
| 1090
|
||||||
|
| 1091
|
||||||
|
| 1092
|
||||||
|
| 1095
|
||||||
|
| 1096
|
||||||
|
| 1097
|
||||||
|
| 1099
|
||||||
|
| 1102
|
||||||
|
| 1124
|
||||||
|
| 1125
|
||||||
|
| 1126
|
||||||
|
| 1129
|
||||||
|
|
||||||
|
interface LaunchShowOption {
|
||||||
|
/** 打开小程序的路径 */
|
||||||
|
path: string
|
||||||
|
/** 打开小程序的query */
|
||||||
|
query: IAnyObject
|
||||||
|
/** 打开小程序的场景值
|
||||||
|
* - 1001:发现栏小程序主入口,「最近使用」列表(基础库2.2.4版本起包含「我的小程序」列表)
|
||||||
|
* - 1005:微信首页顶部搜索框的搜索结果页
|
||||||
|
* - 1006:发现栏小程序主入口搜索框的搜索结果页
|
||||||
|
* - 1007:单人聊天会话中的小程序消息卡片
|
||||||
|
* - 1008:群聊会话中的小程序消息卡片
|
||||||
|
* - 1011:扫描二维码
|
||||||
|
* - 1012:长按图片识别二维码
|
||||||
|
* - 1013:扫描手机相册中选取的二维码
|
||||||
|
* - 1014:小程序模板消息
|
||||||
|
* - 1017:前往小程序体验版的入口页
|
||||||
|
* - 1019:微信钱包(微信客户端7.0.0版本改为支付入口)
|
||||||
|
* - 1020:公众号 profile 页相关小程序列表
|
||||||
|
* - 1023:安卓系统桌面图标
|
||||||
|
* - 1024:小程序 profile 页
|
||||||
|
* - 1025:扫描一维码
|
||||||
|
* - 1026:发现栏小程序主入口,「附近的小程序」列表
|
||||||
|
* - 1027:微信首页顶部搜索框搜索结果页「使用过的小程序」列表
|
||||||
|
* - 1028:我的卡包
|
||||||
|
* - 1029:小程序中的卡券详情页
|
||||||
|
* - 1030:自动化测试下打开小程序
|
||||||
|
* - 1031:长按图片识别一维码
|
||||||
|
* - 1032:扫描手机相册中选取的一维码
|
||||||
|
* - 1034:微信支付完成页
|
||||||
|
* - 1035:公众号自定义菜单
|
||||||
|
* - 1036:App 分享消息卡片
|
||||||
|
* - 1037:小程序打开小程序
|
||||||
|
* - 1038:从另一个小程序返回
|
||||||
|
* - 1039:摇电视
|
||||||
|
* - 1042:添加好友搜索框的搜索结果页
|
||||||
|
* - 1043:公众号模板消息
|
||||||
|
* - 1044:带 shareTicket 的小程序消息卡片 [详情](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share.html)
|
||||||
|
* - 1045:朋友圈广告
|
||||||
|
* - 1046:朋友圈广告详情页
|
||||||
|
* - 1047:扫描小程序码
|
||||||
|
* - 1048:长按图片识别小程序码
|
||||||
|
* - 1049:扫描手机相册中选取的小程序码
|
||||||
|
* - 1052:卡券的适用门店列表
|
||||||
|
* - 1053:搜一搜的结果页
|
||||||
|
* - 1056:聊天顶部音乐播放器右上角菜单
|
||||||
|
* - 1057:钱包中的银行卡详情页
|
||||||
|
* - 1058:公众号文章
|
||||||
|
* - 1059:体验版小程序绑定邀请页
|
||||||
|
* - 1064:微信首页连Wi-Fi状态栏
|
||||||
|
* - 1067:公众号文章广告
|
||||||
|
* - 1069:移动应用
|
||||||
|
* - 1071:钱包中的银行卡列表页
|
||||||
|
* - 1072:二维码收款页面
|
||||||
|
* - 1073:客服消息列表下发的小程序消息卡片
|
||||||
|
* - 1074:公众号会话下发的小程序消息卡片
|
||||||
|
* - 1077:摇周边
|
||||||
|
* - 1078:微信连Wi-Fi成功提示页
|
||||||
|
* - 1079:微信游戏中心
|
||||||
|
* - 1081:客服消息下发的文字链
|
||||||
|
* - 1082:公众号会话下发的文字链
|
||||||
|
* - 1084:朋友圈广告原生页
|
||||||
|
* - 1089:微信聊天主界面下拉,「最近使用」栏(基础库2.2.4版本起包含「我的小程序」栏)
|
||||||
|
* - 1090:长按小程序右上角菜单唤出最近使用历史
|
||||||
|
* - 1091:公众号文章商品卡片
|
||||||
|
* - 1092:城市服务入口
|
||||||
|
* - 1095:小程序广告组件
|
||||||
|
* - 1096:聊天记录
|
||||||
|
* - 1097:微信支付签约页
|
||||||
|
* - 1099:页面内嵌插件
|
||||||
|
* - 1102:公众号 profile 页服务预览
|
||||||
|
* - 1124:扫“一物一码”打开小程序
|
||||||
|
* - 1125:长按图片识别“一物一码”
|
||||||
|
* - 1126:扫描手机相册中选取的“一物一码”
|
||||||
|
* - 1129:微信爬虫访问 [详情](https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/sitemap.html)
|
||||||
|
*/
|
||||||
|
scene: SceneValues
|
||||||
|
/** shareTicket,详见 [获取更多转发信息]((转发#获取更多转发信息)) */
|
||||||
|
shareTicket: string
|
||||||
|
/** 当场景为由从另一个小程序或公众号或App打开时,返回此字段 */
|
||||||
|
referrerInfo?: ReferrerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PageNotFoundOption {
|
||||||
|
/** 不存在页面的路径 */
|
||||||
|
path: string
|
||||||
|
/** 打开不存在页面的 query */
|
||||||
|
query: IAnyObject
|
||||||
|
/** 是否本次启动的首个页面(例如从分享等入口进来,首个页面是开发者配置的分享页面) */
|
||||||
|
isEntryPage: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
/** 生命周期回调—监听小程序初始化
|
||||||
|
*
|
||||||
|
* 小程序初始化完成时触发,全局只触发一次。
|
||||||
|
*/
|
||||||
|
onLaunch(options: LaunchShowOption): void
|
||||||
|
/** 生命周期回调—监听小程序显示
|
||||||
|
*
|
||||||
|
* 小程序启动,或从后台进入前台显示时
|
||||||
|
*/
|
||||||
|
onShow(options: LaunchShowOption): void
|
||||||
|
/** 生命周期回调—监听小程序隐藏
|
||||||
|
*
|
||||||
|
* 小程序从前台进入后台时
|
||||||
|
*/
|
||||||
|
onHide(): void
|
||||||
|
/** 错误监听函数
|
||||||
|
*
|
||||||
|
* 小程序发生脚本错误,或者 api
|
||||||
|
*/
|
||||||
|
onError(/** 错误信息,包含堆栈 */ error: string): void
|
||||||
|
/** 页面不存在监听函数
|
||||||
|
*
|
||||||
|
* 小程序要打开的页面不存在时触发,会带上页面信息回调该函数
|
||||||
|
*
|
||||||
|
* **注意:**
|
||||||
|
* 1. 如果开发者没有添加 `onPageNotFound` 监听,当跳转页面不存在时,将推入微信客户端原生的页面不存在提示页面。
|
||||||
|
* 2. 如果 `onPageNotFound` 回调中又重定向到另一个不存在的页面,将推入微信客户端原生的页面不存在提示页面,并且不再回调 `onPageNotFound`。
|
||||||
|
*
|
||||||
|
* 最低基础库: 1.9.90
|
||||||
|
*/
|
||||||
|
onPageNotFound(options: PageNotFoundOption): void
|
||||||
|
/**
|
||||||
|
* 小程序有未处理的 Promise 拒绝时触发。也可以使用 [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html) 绑定监听。注意事项请参考 [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html)。
|
||||||
|
* **参数**:与 [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html) 一致
|
||||||
|
*/
|
||||||
|
onUnhandledRejection: OnUnhandledRejectionCallback
|
||||||
|
/**
|
||||||
|
* 系统切换主题时触发。也可以使用 wx.onThemeChange 绑定监听。
|
||||||
|
*
|
||||||
|
* 最低基础库: 2.11.0
|
||||||
|
*/
|
||||||
|
onThemeChange: OnThemeChangeCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
type Instance<T extends IAnyObject> = Option & T
|
||||||
|
type Options<T extends IAnyObject> = Partial<Option> &
|
||||||
|
T &
|
||||||
|
ThisType<Instance<T>>
|
||||||
|
type TrivialInstance = Instance<IAnyObject>
|
||||||
|
|
||||||
|
interface Constructor {
|
||||||
|
<T extends IAnyObject>(options: Options<T>): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetAppOption {
|
||||||
|
/** 在 `App` 未定义时返回默认实现。当App被调用时,默认实现中定义的属性会被覆盖合并到App中。一般用于独立分包
|
||||||
|
*
|
||||||
|
* 最低基础库: 2.2.4
|
||||||
|
*/
|
||||||
|
allowDefault?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetApp {
|
||||||
|
<T = IAnyObject>(opts?: GetAppOption): Instance<T>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare let App: WechatMiniprogram.App.Constructor
|
||||||
|
declare let getApp: WechatMiniprogram.App.GetApp
|
||||||
68
frontend_miniprogram/typings/types/wx/lib.wx.behavior.d.ts
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
declare namespace WechatMiniprogram.Behavior {
|
||||||
|
type BehaviorIdentifier = string
|
||||||
|
type Instance<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends MethodOption,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = Record<string, never>
|
||||||
|
> = Component.Instance<TData, TProperty, TMethod, TCustomInstanceProperty>
|
||||||
|
type TrivialInstance = Instance<IAnyObject, IAnyObject, IAnyObject>
|
||||||
|
type TrivialOption = Options<IAnyObject, IAnyObject, IAnyObject>
|
||||||
|
type Options<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends MethodOption,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = Record<string, never>
|
||||||
|
> = Partial<Data<TData>> &
|
||||||
|
Partial<Property<TProperty>> &
|
||||||
|
Partial<Method<TMethod>> &
|
||||||
|
Partial<OtherOption> &
|
||||||
|
Partial<Lifetimes> &
|
||||||
|
ThisType<Instance<TData, TProperty, TMethod, TCustomInstanceProperty>>
|
||||||
|
interface Constructor {
|
||||||
|
<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends MethodOption,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = Record<string, never>
|
||||||
|
>(
|
||||||
|
options: Options<TData, TProperty, TMethod, TCustomInstanceProperty>
|
||||||
|
): BehaviorIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataOption = Component.DataOption
|
||||||
|
type PropertyOption = Component.PropertyOption
|
||||||
|
type MethodOption = Component.MethodOption
|
||||||
|
type Data<D extends DataOption> = Component.Data<D>
|
||||||
|
type Property<P extends PropertyOption> = Component.Property<P>
|
||||||
|
type Method<M extends MethodOption> = Component.Method<M>
|
||||||
|
|
||||||
|
type DefinitionFilter = Component.DefinitionFilter
|
||||||
|
type Lifetimes = Component.Lifetimes
|
||||||
|
|
||||||
|
type OtherOption = Omit<Component.OtherOption, 'options'>
|
||||||
|
}
|
||||||
|
/** 注册一个 `behavior`,接受一个 `Object` 类型的参数。*/
|
||||||
|
declare let Behavior: WechatMiniprogram.Behavior.Constructor
|
||||||
924
frontend_miniprogram/typings/types/wx/lib.wx.cloud.d.ts
vendored
Normal file
@@ -0,0 +1,924 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
interface IAPIError {
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAPIParam<T = any> {
|
||||||
|
config?: ICloudConfig
|
||||||
|
success?: (res: T) => void
|
||||||
|
fail?: (err: IAPIError) => void
|
||||||
|
complete?: (val: T | IAPIError) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAPISuccessParam {
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type IAPICompleteParam = IAPISuccessParam | IAPIError
|
||||||
|
|
||||||
|
type IAPIFunction<T, P extends IAPIParam<T>> = (param?: P) => Promise<T>
|
||||||
|
|
||||||
|
interface IInitCloudConfig {
|
||||||
|
env?:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
database?: string
|
||||||
|
functions?: string
|
||||||
|
storage?: string
|
||||||
|
}
|
||||||
|
traceUser?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICloudConfig {
|
||||||
|
env?: string
|
||||||
|
traceUser?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IICloudAPI {
|
||||||
|
init: (config?: IInitCloudConfig) => void
|
||||||
|
[api: string]: AnyFunction | IAPIFunction<any, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICloudService {
|
||||||
|
name: string
|
||||||
|
|
||||||
|
getAPIs: () => { [name: string]: IAPIFunction<any, any> }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICloudServices {
|
||||||
|
[serviceName: string]: ICloudService
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICloudMetaData {
|
||||||
|
session_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
declare class InternalSymbol {}
|
||||||
|
|
||||||
|
interface AnyObject {
|
||||||
|
[x: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnyArray = any[]
|
||||||
|
|
||||||
|
type AnyFunction = (...args: any[]) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extend wx with cloud
|
||||||
|
*/
|
||||||
|
interface WxCloud {
|
||||||
|
init: (config?: ICloudConfig) => void
|
||||||
|
|
||||||
|
callFunction(param: OQ<ICloud.CallFunctionParam>): void
|
||||||
|
callFunction(
|
||||||
|
param: RQ<ICloud.CallFunctionParam>
|
||||||
|
): Promise<ICloud.CallFunctionResult>
|
||||||
|
|
||||||
|
uploadFile(param: OQ<ICloud.UploadFileParam>): WechatMiniprogram.UploadTask
|
||||||
|
uploadFile(
|
||||||
|
param: RQ<ICloud.UploadFileParam>
|
||||||
|
): Promise<ICloud.UploadFileResult>
|
||||||
|
|
||||||
|
downloadFile(
|
||||||
|
param: OQ<ICloud.DownloadFileParam>
|
||||||
|
): WechatMiniprogram.DownloadTask
|
||||||
|
downloadFile(
|
||||||
|
param: RQ<ICloud.DownloadFileParam>
|
||||||
|
): Promise<ICloud.DownloadFileResult>
|
||||||
|
|
||||||
|
getTempFileURL(param: OQ<ICloud.GetTempFileURLParam>): void
|
||||||
|
getTempFileURL(
|
||||||
|
param: RQ<ICloud.GetTempFileURLParam>
|
||||||
|
): Promise<ICloud.GetTempFileURLResult>
|
||||||
|
|
||||||
|
deleteFile(param: OQ<ICloud.DeleteFileParam>): void
|
||||||
|
deleteFile(
|
||||||
|
param: RQ<ICloud.DeleteFileParam>
|
||||||
|
): Promise<ICloud.DeleteFileResult>
|
||||||
|
|
||||||
|
database: (config?: ICloudConfig) => DB.Database
|
||||||
|
|
||||||
|
CloudID: ICloud.ICloudIDConstructor
|
||||||
|
CDN: ICloud.ICDNConstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace ICloud {
|
||||||
|
interface ICloudAPIParam<T = any> extends IAPIParam<T> {
|
||||||
|
config?: ICloudConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// === API: callFunction ===
|
||||||
|
type CallFunctionData = AnyObject
|
||||||
|
|
||||||
|
interface CallFunctionResult extends IAPISuccessParam {
|
||||||
|
result: AnyObject | string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CallFunctionParam extends ICloudAPIParam<CallFunctionResult> {
|
||||||
|
name: string
|
||||||
|
data?: CallFunctionData
|
||||||
|
slow?: boolean
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: uploadFile ===
|
||||||
|
interface UploadFileResult extends IAPISuccessParam {
|
||||||
|
fileID: string
|
||||||
|
statusCode: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UploadFileParam extends ICloudAPIParam<UploadFileResult> {
|
||||||
|
cloudPath: string
|
||||||
|
filePath: string
|
||||||
|
header?: AnyObject
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: downloadFile ===
|
||||||
|
interface DownloadFileResult extends IAPISuccessParam {
|
||||||
|
tempFilePath: string
|
||||||
|
statusCode: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DownloadFileParam extends ICloudAPIParam<DownloadFileResult> {
|
||||||
|
fileID: string
|
||||||
|
cloudPath?: string
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: getTempFileURL ===
|
||||||
|
interface GetTempFileURLResult extends IAPISuccessParam {
|
||||||
|
fileList: GetTempFileURLResultItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetTempFileURLResultItem {
|
||||||
|
fileID: string
|
||||||
|
tempFileURL: string
|
||||||
|
maxAge: number
|
||||||
|
status: number
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetTempFileURLParam extends ICloudAPIParam<GetTempFileURLResult> {
|
||||||
|
fileList: string[]
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: deleteFile ===
|
||||||
|
interface DeleteFileResult extends IAPISuccessParam {
|
||||||
|
fileList: DeleteFileResultItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFileResultItem {
|
||||||
|
fileID: string
|
||||||
|
status: number
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFileParam extends ICloudAPIParam<DeleteFileResult> {
|
||||||
|
fileList: string[]
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: CloudID ===
|
||||||
|
abstract class CloudID {
|
||||||
|
constructor(cloudID: string)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICloudIDConstructor {
|
||||||
|
new (cloudId: string): CloudID
|
||||||
|
(cloudId: string): CloudID
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
|
||||||
|
// === API: CDN ===
|
||||||
|
abstract class CDN {
|
||||||
|
target: string | ArrayBuffer | ICDNFilePathSpec
|
||||||
|
constructor(target: string | ArrayBuffer | ICDNFilePathSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICDNFilePathSpec {
|
||||||
|
type: 'filePath'
|
||||||
|
filePath: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICDNConstructor {
|
||||||
|
new (options: string | ArrayBuffer | ICDNFilePathSpec): CDN
|
||||||
|
(options: string | ArrayBuffer | ICDNFilePathSpec): CDN
|
||||||
|
}
|
||||||
|
// === end ===
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Database ===
|
||||||
|
declare namespace DB {
|
||||||
|
/**
|
||||||
|
* The class of all exposed cloud database instances
|
||||||
|
*/
|
||||||
|
class Database {
|
||||||
|
readonly config: ICloudConfig
|
||||||
|
readonly command: DatabaseCommand
|
||||||
|
readonly Geo: IGeo
|
||||||
|
readonly serverDate: () => ServerDate
|
||||||
|
readonly RegExp: IRegExpConstructor
|
||||||
|
|
||||||
|
private constructor()
|
||||||
|
|
||||||
|
collection(collectionName: string): CollectionReference
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionReference extends Query {
|
||||||
|
readonly collectionName: string
|
||||||
|
|
||||||
|
private constructor(name: string, database: Database)
|
||||||
|
|
||||||
|
doc(docId: string | number): DocumentReference
|
||||||
|
|
||||||
|
add(options: OQ<IAddDocumentOptions>): void
|
||||||
|
add(options: RQ<IAddDocumentOptions>): Promise<IAddResult>
|
||||||
|
}
|
||||||
|
|
||||||
|
class DocumentReference {
|
||||||
|
private constructor(docId: string | number, database: Database)
|
||||||
|
|
||||||
|
field(object: Record<string, any>): this
|
||||||
|
|
||||||
|
get(options: OQ<IGetDocumentOptions>): void
|
||||||
|
get(options?: RQ<IGetDocumentOptions>): Promise<IQuerySingleResult>
|
||||||
|
|
||||||
|
set(options: OQ<ISetSingleDocumentOptions>): void
|
||||||
|
set(options?: RQ<ISetSingleDocumentOptions>): Promise<ISetResult>
|
||||||
|
|
||||||
|
update(options: OQ<IUpdateSingleDocumentOptions>): void
|
||||||
|
update(
|
||||||
|
options?: RQ<IUpdateSingleDocumentOptions>
|
||||||
|
): Promise<IUpdateResult>
|
||||||
|
|
||||||
|
remove(options: OQ<IRemoveSingleDocumentOptions>): void
|
||||||
|
remove(
|
||||||
|
options?: RQ<IRemoveSingleDocumentOptions>
|
||||||
|
): Promise<IRemoveResult>
|
||||||
|
|
||||||
|
watch(options: IWatchOptions): RealtimeListener
|
||||||
|
}
|
||||||
|
|
||||||
|
class RealtimeListener {
|
||||||
|
// "And Now His Watch Is Ended"
|
||||||
|
close: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Query {
|
||||||
|
where(condition: IQueryCondition): Query
|
||||||
|
|
||||||
|
orderBy(fieldPath: string, order: string): Query
|
||||||
|
|
||||||
|
limit(max: number): Query
|
||||||
|
|
||||||
|
skip(offset: number): Query
|
||||||
|
|
||||||
|
field(object: Record<string, any>): Query
|
||||||
|
|
||||||
|
get(options: OQ<IGetDocumentOptions>): void
|
||||||
|
get(options?: RQ<IGetDocumentOptions>): Promise<IQueryResult>
|
||||||
|
|
||||||
|
count(options: OQ<ICountDocumentOptions>): void
|
||||||
|
count(options?: RQ<ICountDocumentOptions>): Promise<ICountResult>
|
||||||
|
|
||||||
|
watch(options: IWatchOptions): RealtimeListener
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DatabaseCommand {
|
||||||
|
eq(val: any): DatabaseQueryCommand
|
||||||
|
neq(val: any): DatabaseQueryCommand
|
||||||
|
gt(val: any): DatabaseQueryCommand
|
||||||
|
gte(val: any): DatabaseQueryCommand
|
||||||
|
lt(val: any): DatabaseQueryCommand
|
||||||
|
lte(val: any): DatabaseQueryCommand
|
||||||
|
in(val: any[]): DatabaseQueryCommand
|
||||||
|
nin(val: any[]): DatabaseQueryCommand
|
||||||
|
|
||||||
|
geoNear(options: IGeoNearCommandOptions): DatabaseQueryCommand
|
||||||
|
geoWithin(options: IGeoWithinCommandOptions): DatabaseQueryCommand
|
||||||
|
geoIntersects(
|
||||||
|
options: IGeoIntersectsCommandOptions
|
||||||
|
): DatabaseQueryCommand
|
||||||
|
|
||||||
|
and(
|
||||||
|
...expressions: Array<DatabaseLogicCommand | IQueryCondition>
|
||||||
|
): DatabaseLogicCommand
|
||||||
|
or(
|
||||||
|
...expressions: Array<DatabaseLogicCommand | IQueryCondition>
|
||||||
|
): DatabaseLogicCommand
|
||||||
|
nor(
|
||||||
|
...expressions: Array<DatabaseLogicCommand | IQueryCondition>
|
||||||
|
): DatabaseLogicCommand
|
||||||
|
not(expression: DatabaseLogicCommand): DatabaseLogicCommand
|
||||||
|
|
||||||
|
exists(val: boolean): DatabaseQueryCommand
|
||||||
|
|
||||||
|
mod(divisor: number, remainder: number): DatabaseQueryCommand
|
||||||
|
|
||||||
|
all(val: any[]): DatabaseQueryCommand
|
||||||
|
elemMatch(val: any): DatabaseQueryCommand
|
||||||
|
size(val: number): DatabaseQueryCommand
|
||||||
|
|
||||||
|
set(val: any): DatabaseUpdateCommand
|
||||||
|
remove(): DatabaseUpdateCommand
|
||||||
|
inc(val: number): DatabaseUpdateCommand
|
||||||
|
mul(val: number): DatabaseUpdateCommand
|
||||||
|
min(val: number): DatabaseUpdateCommand
|
||||||
|
max(val: number): DatabaseUpdateCommand
|
||||||
|
rename(val: string): DatabaseUpdateCommand
|
||||||
|
bit(val: number): DatabaseUpdateCommand
|
||||||
|
|
||||||
|
push(...values: any[]): DatabaseUpdateCommand
|
||||||
|
pop(): DatabaseUpdateCommand
|
||||||
|
shift(): DatabaseUpdateCommand
|
||||||
|
unshift(...values: any[]): DatabaseUpdateCommand
|
||||||
|
addToSet(val: any): DatabaseUpdateCommand
|
||||||
|
pull(val: any): DatabaseUpdateCommand
|
||||||
|
pullAll(val: any): DatabaseUpdateCommand
|
||||||
|
|
||||||
|
project: {
|
||||||
|
slice(val: number | [number, number]): DatabaseProjectionCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate: {
|
||||||
|
__safe_props__?: Set<string>
|
||||||
|
|
||||||
|
abs(val: any): DatabaseAggregateCommand
|
||||||
|
add(val: any): DatabaseAggregateCommand
|
||||||
|
addToSet(val: any): DatabaseAggregateCommand
|
||||||
|
allElementsTrue(val: any): DatabaseAggregateCommand
|
||||||
|
and(val: any): DatabaseAggregateCommand
|
||||||
|
anyElementTrue(val: any): DatabaseAggregateCommand
|
||||||
|
arrayElemAt(val: any): DatabaseAggregateCommand
|
||||||
|
arrayToObject(val: any): DatabaseAggregateCommand
|
||||||
|
avg(val: any): DatabaseAggregateCommand
|
||||||
|
ceil(val: any): DatabaseAggregateCommand
|
||||||
|
cmp(val: any): DatabaseAggregateCommand
|
||||||
|
concat(val: any): DatabaseAggregateCommand
|
||||||
|
concatArrays(val: any): DatabaseAggregateCommand
|
||||||
|
cond(val: any): DatabaseAggregateCommand
|
||||||
|
convert(val: any): DatabaseAggregateCommand
|
||||||
|
dateFromParts(val: any): DatabaseAggregateCommand
|
||||||
|
dateToParts(val: any): DatabaseAggregateCommand
|
||||||
|
dateFromString(val: any): DatabaseAggregateCommand
|
||||||
|
dateToString(val: any): DatabaseAggregateCommand
|
||||||
|
dayOfMonth(val: any): DatabaseAggregateCommand
|
||||||
|
dayOfWeek(val: any): DatabaseAggregateCommand
|
||||||
|
dayOfYear(val: any): DatabaseAggregateCommand
|
||||||
|
divide(val: any): DatabaseAggregateCommand
|
||||||
|
eq(val: any): DatabaseAggregateCommand
|
||||||
|
exp(val: any): DatabaseAggregateCommand
|
||||||
|
filter(val: any): DatabaseAggregateCommand
|
||||||
|
first(val: any): DatabaseAggregateCommand
|
||||||
|
floor(val: any): DatabaseAggregateCommand
|
||||||
|
gt(val: any): DatabaseAggregateCommand
|
||||||
|
gte(val: any): DatabaseAggregateCommand
|
||||||
|
hour(val: any): DatabaseAggregateCommand
|
||||||
|
ifNull(val: any): DatabaseAggregateCommand
|
||||||
|
in(val: any): DatabaseAggregateCommand
|
||||||
|
indexOfArray(val: any): DatabaseAggregateCommand
|
||||||
|
indexOfBytes(val: any): DatabaseAggregateCommand
|
||||||
|
indexOfCP(val: any): DatabaseAggregateCommand
|
||||||
|
isArray(val: any): DatabaseAggregateCommand
|
||||||
|
isoDayOfWeek(val: any): DatabaseAggregateCommand
|
||||||
|
isoWeek(val: any): DatabaseAggregateCommand
|
||||||
|
isoWeekYear(val: any): DatabaseAggregateCommand
|
||||||
|
last(val: any): DatabaseAggregateCommand
|
||||||
|
let(val: any): DatabaseAggregateCommand
|
||||||
|
literal(val: any): DatabaseAggregateCommand
|
||||||
|
ln(val: any): DatabaseAggregateCommand
|
||||||
|
log(val: any): DatabaseAggregateCommand
|
||||||
|
log10(val: any): DatabaseAggregateCommand
|
||||||
|
lt(val: any): DatabaseAggregateCommand
|
||||||
|
lte(val: any): DatabaseAggregateCommand
|
||||||
|
ltrim(val: any): DatabaseAggregateCommand
|
||||||
|
map(val: any): DatabaseAggregateCommand
|
||||||
|
max(val: any): DatabaseAggregateCommand
|
||||||
|
mergeObjects(val: any): DatabaseAggregateCommand
|
||||||
|
meta(val: any): DatabaseAggregateCommand
|
||||||
|
min(val: any): DatabaseAggregateCommand
|
||||||
|
millisecond(val: any): DatabaseAggregateCommand
|
||||||
|
minute(val: any): DatabaseAggregateCommand
|
||||||
|
mod(val: any): DatabaseAggregateCommand
|
||||||
|
month(val: any): DatabaseAggregateCommand
|
||||||
|
multiply(val: any): DatabaseAggregateCommand
|
||||||
|
neq(val: any): DatabaseAggregateCommand
|
||||||
|
not(val: any): DatabaseAggregateCommand
|
||||||
|
objectToArray(val: any): DatabaseAggregateCommand
|
||||||
|
or(val: any): DatabaseAggregateCommand
|
||||||
|
pow(val: any): DatabaseAggregateCommand
|
||||||
|
push(val: any): DatabaseAggregateCommand
|
||||||
|
range(val: any): DatabaseAggregateCommand
|
||||||
|
reduce(val: any): DatabaseAggregateCommand
|
||||||
|
reverseArray(val: any): DatabaseAggregateCommand
|
||||||
|
rtrim(val: any): DatabaseAggregateCommand
|
||||||
|
second(val: any): DatabaseAggregateCommand
|
||||||
|
setDifference(val: any): DatabaseAggregateCommand
|
||||||
|
setEquals(val: any): DatabaseAggregateCommand
|
||||||
|
setIntersection(val: any): DatabaseAggregateCommand
|
||||||
|
setIsSubset(val: any): DatabaseAggregateCommand
|
||||||
|
setUnion(val: any): DatabaseAggregateCommand
|
||||||
|
size(val: any): DatabaseAggregateCommand
|
||||||
|
slice(val: any): DatabaseAggregateCommand
|
||||||
|
split(val: any): DatabaseAggregateCommand
|
||||||
|
sqrt(val: any): DatabaseAggregateCommand
|
||||||
|
stdDevPop(val: any): DatabaseAggregateCommand
|
||||||
|
stdDevSamp(val: any): DatabaseAggregateCommand
|
||||||
|
strcasecmp(val: any): DatabaseAggregateCommand
|
||||||
|
strLenBytes(val: any): DatabaseAggregateCommand
|
||||||
|
strLenCP(val: any): DatabaseAggregateCommand
|
||||||
|
substr(val: any): DatabaseAggregateCommand
|
||||||
|
substrBytes(val: any): DatabaseAggregateCommand
|
||||||
|
substrCP(val: any): DatabaseAggregateCommand
|
||||||
|
subtract(val: any): DatabaseAggregateCommand
|
||||||
|
sum(val: any): DatabaseAggregateCommand
|
||||||
|
switch(val: any): DatabaseAggregateCommand
|
||||||
|
toBool(val: any): DatabaseAggregateCommand
|
||||||
|
toDate(val: any): DatabaseAggregateCommand
|
||||||
|
toDecimal(val: any): DatabaseAggregateCommand
|
||||||
|
toDouble(val: any): DatabaseAggregateCommand
|
||||||
|
toInt(val: any): DatabaseAggregateCommand
|
||||||
|
toLong(val: any): DatabaseAggregateCommand
|
||||||
|
toObjectId(val: any): DatabaseAggregateCommand
|
||||||
|
toString(val: any): DatabaseAggregateCommand
|
||||||
|
toLower(val: any): DatabaseAggregateCommand
|
||||||
|
toUpper(val: any): DatabaseAggregateCommand
|
||||||
|
trim(val: any): DatabaseAggregateCommand
|
||||||
|
trunc(val: any): DatabaseAggregateCommand
|
||||||
|
type(val: any): DatabaseAggregateCommand
|
||||||
|
week(val: any): DatabaseAggregateCommand
|
||||||
|
year(val: any): DatabaseAggregateCommand
|
||||||
|
zip(val: any): DatabaseAggregateCommand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseAggregateCommand {}
|
||||||
|
|
||||||
|
enum LOGIC_COMMANDS_LITERAL {
|
||||||
|
AND = 'and',
|
||||||
|
OR = 'or',
|
||||||
|
NOT = 'not',
|
||||||
|
NOR = 'nor'
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseLogicCommand {
|
||||||
|
and(...expressions: DatabaseLogicCommand[]): DatabaseLogicCommand
|
||||||
|
or(...expressions: DatabaseLogicCommand[]): DatabaseLogicCommand
|
||||||
|
nor(...expressions: DatabaseLogicCommand[]): DatabaseLogicCommand
|
||||||
|
not(expression: DatabaseLogicCommand): DatabaseLogicCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
enum QUERY_COMMANDS_LITERAL {
|
||||||
|
// comparison
|
||||||
|
EQ = 'eq',
|
||||||
|
NEQ = 'neq',
|
||||||
|
GT = 'gt',
|
||||||
|
GTE = 'gte',
|
||||||
|
LT = 'lt',
|
||||||
|
LTE = 'lte',
|
||||||
|
IN = 'in',
|
||||||
|
NIN = 'nin',
|
||||||
|
// geo
|
||||||
|
GEO_NEAR = 'geoNear',
|
||||||
|
GEO_WITHIN = 'geoWithin',
|
||||||
|
GEO_INTERSECTS = 'geoIntersects',
|
||||||
|
// element
|
||||||
|
EXISTS = 'exists',
|
||||||
|
// evaluation
|
||||||
|
MOD = 'mod',
|
||||||
|
// array
|
||||||
|
ALL = 'all',
|
||||||
|
ELEM_MATCH = 'elemMatch',
|
||||||
|
SIZE = 'size'
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseQueryCommand extends DatabaseLogicCommand {
|
||||||
|
eq(val: any): DatabaseLogicCommand
|
||||||
|
neq(val: any): DatabaseLogicCommand
|
||||||
|
gt(val: any): DatabaseLogicCommand
|
||||||
|
gte(val: any): DatabaseLogicCommand
|
||||||
|
lt(val: any): DatabaseLogicCommand
|
||||||
|
lte(val: any): DatabaseLogicCommand
|
||||||
|
in(val: any[]): DatabaseLogicCommand
|
||||||
|
nin(val: any[]): DatabaseLogicCommand
|
||||||
|
|
||||||
|
exists(val: boolean): DatabaseLogicCommand
|
||||||
|
|
||||||
|
mod(divisor: number, remainder: number): DatabaseLogicCommand
|
||||||
|
|
||||||
|
all(val: any[]): DatabaseLogicCommand
|
||||||
|
elemMatch(val: any): DatabaseLogicCommand
|
||||||
|
size(val: number): DatabaseLogicCommand
|
||||||
|
|
||||||
|
geoNear(options: IGeoNearCommandOptions): DatabaseLogicCommand
|
||||||
|
geoWithin(options: IGeoWithinCommandOptions): DatabaseLogicCommand
|
||||||
|
geoIntersects(
|
||||||
|
options: IGeoIntersectsCommandOptions
|
||||||
|
): DatabaseLogicCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PROJECTION_COMMANDS_LITERAL {
|
||||||
|
SLICE = 'slice'
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseProjectionCommand {}
|
||||||
|
|
||||||
|
enum UPDATE_COMMANDS_LITERAL {
|
||||||
|
// field
|
||||||
|
SET = 'set',
|
||||||
|
REMOVE = 'remove',
|
||||||
|
INC = 'inc',
|
||||||
|
MUL = 'mul',
|
||||||
|
MIN = 'min',
|
||||||
|
MAX = 'max',
|
||||||
|
RENAME = 'rename',
|
||||||
|
// bitwise
|
||||||
|
BIT = 'bit',
|
||||||
|
// array
|
||||||
|
PUSH = 'push',
|
||||||
|
POP = 'pop',
|
||||||
|
SHIFT = 'shift',
|
||||||
|
UNSHIFT = 'unshift',
|
||||||
|
ADD_TO_SET = 'addToSet',
|
||||||
|
PULL = 'pull',
|
||||||
|
PULL_ALL = 'pullAll'
|
||||||
|
}
|
||||||
|
|
||||||
|
class DatabaseUpdateCommand {}
|
||||||
|
|
||||||
|
class Batch {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contract that all API provider must adhere to
|
||||||
|
*/
|
||||||
|
class APIBaseContract<
|
||||||
|
PromiseReturn,
|
||||||
|
CallbackReturn,
|
||||||
|
Param extends IAPIParam,
|
||||||
|
Context = any
|
||||||
|
> {
|
||||||
|
getContext(param: Param): Context
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case of callback-style invocation, this function will be called
|
||||||
|
*/
|
||||||
|
getCallbackReturn(param: Param, context: Context): CallbackReturn
|
||||||
|
|
||||||
|
getFinalParam<T extends Param>(param: Param, context: Context): T
|
||||||
|
|
||||||
|
run<T extends Param>(param: T): Promise<PromiseReturn>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoPointConstructor {
|
||||||
|
new (longitude: number, latitide: number): GeoPoint
|
||||||
|
new (geojson: IGeoJSONPoint): GeoPoint
|
||||||
|
(longitude: number, latitide: number): GeoPoint
|
||||||
|
(geojson: IGeoJSONPoint): GeoPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoMultiPointConstructor {
|
||||||
|
new (points: GeoPoint[] | IGeoJSONMultiPoint): GeoMultiPoint
|
||||||
|
(points: GeoPoint[] | IGeoJSONMultiPoint): GeoMultiPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoLineStringConstructor {
|
||||||
|
new (points: GeoPoint[] | IGeoJSONLineString): GeoLineString
|
||||||
|
(points: GeoPoint[] | IGeoJSONLineString): GeoLineString
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoMultiLineStringConstructor {
|
||||||
|
new (
|
||||||
|
lineStrings: GeoLineString[] | IGeoJSONMultiLineString
|
||||||
|
): GeoMultiLineString
|
||||||
|
(
|
||||||
|
lineStrings: GeoLineString[] | IGeoJSONMultiLineString
|
||||||
|
): GeoMultiLineString
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoPolygonConstructor {
|
||||||
|
new (lineStrings: GeoLineString[] | IGeoJSONPolygon): GeoPolygon
|
||||||
|
(lineStrings: GeoLineString[] | IGeoJSONPolygon): GeoPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoMultiPolygonConstructor {
|
||||||
|
new (polygons: GeoPolygon[] | IGeoJSONMultiPolygon): GeoMultiPolygon
|
||||||
|
(polygons: GeoPolygon[] | IGeoJSONMultiPolygon): GeoMultiPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeo {
|
||||||
|
Point: IGeoPointConstructor
|
||||||
|
MultiPoint: IGeoMultiPointConstructor
|
||||||
|
LineString: IGeoLineStringConstructor
|
||||||
|
MultiLineString: IGeoMultiLineStringConstructor
|
||||||
|
Polygon: IGeoPolygonConstructor
|
||||||
|
MultiPolygon: IGeoMultiPolygonConstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONPoint {
|
||||||
|
type: 'Point'
|
||||||
|
coordinates: [number, number]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONMultiPoint {
|
||||||
|
type: 'MultiPoint'
|
||||||
|
coordinates: Array<[number, number]>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONLineString {
|
||||||
|
type: 'LineString'
|
||||||
|
coordinates: Array<[number, number]>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONMultiLineString {
|
||||||
|
type: 'MultiLineString'
|
||||||
|
coordinates: Array<Array<[number, number]>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONPolygon {
|
||||||
|
type: 'Polygon'
|
||||||
|
coordinates: Array<Array<[number, number]>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoJSONMultiPolygon {
|
||||||
|
type: 'MultiPolygon'
|
||||||
|
coordinates: Array<Array<Array<[number, number]>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
type IGeoJSONObject =
|
||||||
|
| IGeoJSONPoint
|
||||||
|
| IGeoJSONMultiPoint
|
||||||
|
| IGeoJSONLineString
|
||||||
|
| IGeoJSONMultiLineString
|
||||||
|
| IGeoJSONPolygon
|
||||||
|
| IGeoJSONMultiPolygon
|
||||||
|
|
||||||
|
abstract class GeoPoint {
|
||||||
|
longitude: number
|
||||||
|
latitude: number
|
||||||
|
|
||||||
|
constructor(longitude: number, latitude: number)
|
||||||
|
|
||||||
|
toJSON(): Record<string, any>
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GeoMultiPoint {
|
||||||
|
points: GeoPoint[]
|
||||||
|
|
||||||
|
constructor(points: GeoPoint[])
|
||||||
|
|
||||||
|
toJSON(): IGeoJSONMultiPoint
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GeoLineString {
|
||||||
|
points: GeoPoint[]
|
||||||
|
|
||||||
|
constructor(points: GeoPoint[])
|
||||||
|
|
||||||
|
toJSON(): IGeoJSONLineString
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GeoMultiLineString {
|
||||||
|
lines: GeoLineString[]
|
||||||
|
|
||||||
|
constructor(lines: GeoLineString[])
|
||||||
|
|
||||||
|
toJSON(): IGeoJSONMultiLineString
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GeoPolygon {
|
||||||
|
lines: GeoLineString[]
|
||||||
|
|
||||||
|
constructor(lines: GeoLineString[])
|
||||||
|
|
||||||
|
toJSON(): IGeoJSONPolygon
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GeoMultiPolygon {
|
||||||
|
polygons: GeoPolygon[]
|
||||||
|
|
||||||
|
constructor(polygons: GeoPolygon[])
|
||||||
|
|
||||||
|
toJSON(): IGeoJSONMultiPolygon
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GeoInstance =
|
||||||
|
| GeoPoint
|
||||||
|
| GeoMultiPoint
|
||||||
|
| GeoLineString
|
||||||
|
| GeoMultiLineString
|
||||||
|
| GeoPolygon
|
||||||
|
| GeoMultiPolygon
|
||||||
|
|
||||||
|
interface IGeoNearCommandOptions {
|
||||||
|
geometry: GeoPoint
|
||||||
|
maxDistance?: number
|
||||||
|
minDistance?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoWithinCommandOptions {
|
||||||
|
geometry: GeoPolygon | GeoMultiPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IGeoIntersectsCommandOptions {
|
||||||
|
geometry:
|
||||||
|
| GeoPoint
|
||||||
|
| GeoMultiPoint
|
||||||
|
| GeoLineString
|
||||||
|
| GeoMultiLineString
|
||||||
|
| GeoPolygon
|
||||||
|
| GeoMultiPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IServerDateOptions {
|
||||||
|
offset: number
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ServerDate {
|
||||||
|
readonly options: IServerDateOptions
|
||||||
|
constructor(options?: IServerDateOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRegExpOptions {
|
||||||
|
regexp: string
|
||||||
|
options?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRegExpConstructor {
|
||||||
|
new (options: IRegExpOptions): RegExp
|
||||||
|
(options: IRegExpOptions): RegExp
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class RegExp {
|
||||||
|
readonly regexp: string
|
||||||
|
readonly options: string
|
||||||
|
constructor(options: IRegExpOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DocumentId = string | number
|
||||||
|
|
||||||
|
interface IDocumentData {
|
||||||
|
_id?: DocumentId
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type IDBAPIParam = IAPIParam
|
||||||
|
|
||||||
|
interface IAddDocumentOptions extends IDBAPIParam {
|
||||||
|
data: IDocumentData
|
||||||
|
}
|
||||||
|
|
||||||
|
type IGetDocumentOptions = IDBAPIParam
|
||||||
|
|
||||||
|
type ICountDocumentOptions = IDBAPIParam
|
||||||
|
|
||||||
|
interface IUpdateDocumentOptions extends IDBAPIParam {
|
||||||
|
data: IUpdateCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUpdateSingleDocumentOptions extends IDBAPIParam {
|
||||||
|
data: IUpdateCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetDocumentOptions extends IDBAPIParam {
|
||||||
|
data: IUpdateCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetSingleDocumentOptions extends IDBAPIParam {
|
||||||
|
data: IUpdateCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRemoveDocumentOptions extends IDBAPIParam {
|
||||||
|
query: IQueryCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRemoveSingleDocumentOptions = IDBAPIParam
|
||||||
|
|
||||||
|
interface IWatchOptions {
|
||||||
|
// server realtime data init & change event
|
||||||
|
onChange: (snapshot: ISnapshot) => void
|
||||||
|
// error while connecting / listening
|
||||||
|
onError: (error: any) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISnapshot {
|
||||||
|
id: number
|
||||||
|
docChanges: ISingleDBEvent[]
|
||||||
|
docs: Record<string, any>
|
||||||
|
type?: SnapshotType
|
||||||
|
}
|
||||||
|
|
||||||
|
type SnapshotType = 'init'
|
||||||
|
|
||||||
|
interface ISingleDBEvent {
|
||||||
|
id: number
|
||||||
|
dataType: DataType
|
||||||
|
queueType: QueueType
|
||||||
|
docId: string
|
||||||
|
doc: Record<string, any>
|
||||||
|
updatedFields?: Record<string, any>
|
||||||
|
removedFields?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataType = 'init' | 'update' | 'replace' | 'add' | 'remove' | 'limit'
|
||||||
|
|
||||||
|
type QueueType = 'init' | 'enqueue' | 'dequeue' | 'update'
|
||||||
|
|
||||||
|
interface IQueryCondition {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type IStringQueryCondition = string
|
||||||
|
|
||||||
|
interface IQueryResult extends IAPISuccessParam {
|
||||||
|
data: IDocumentData[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IQuerySingleResult extends IAPISuccessParam {
|
||||||
|
data: IDocumentData
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUpdateCondition {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type IStringUpdateCondition = string
|
||||||
|
|
||||||
|
interface IAddResult extends IAPISuccessParam {
|
||||||
|
_id: DocumentId
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUpdateResult extends IAPISuccessParam {
|
||||||
|
stats: {
|
||||||
|
updated: number
|
||||||
|
// created: number,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISetResult extends IAPISuccessParam {
|
||||||
|
_id: DocumentId
|
||||||
|
stats: {
|
||||||
|
updated: number
|
||||||
|
created: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRemoveResult extends IAPISuccessParam {
|
||||||
|
stats: {
|
||||||
|
removed: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICountResult extends IAPISuccessParam {
|
||||||
|
total: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Optional<T> = { [K in keyof T]+?: T[K] }
|
||||||
|
|
||||||
|
type OQ<
|
||||||
|
T extends Optional<
|
||||||
|
Record<'complete' | 'success' | 'fail', (...args: any[]) => any>
|
||||||
|
>
|
||||||
|
> =
|
||||||
|
| (RQ<T> & Required<Pick<T, 'success'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'fail'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'complete'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'success' | 'fail'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'success' | 'complete'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'fail' | 'complete'>>)
|
||||||
|
| (RQ<T> & Required<Pick<T, 'fail' | 'complete' | 'success'>>)
|
||||||
|
|
||||||
|
type RQ<
|
||||||
|
T extends Optional<
|
||||||
|
Record<'complete' | 'success' | 'fail', (...args: any[]) => any>
|
||||||
|
>
|
||||||
|
> = Pick<T, Exclude<keyof T, 'complete' | 'success' | 'fail'>>
|
||||||
636
frontend_miniprogram/typings/types/wx/lib.wx.component.d.ts
vendored
Normal file
@@ -0,0 +1,636 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
declare namespace WechatMiniprogram.Component {
|
||||||
|
type Instance<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends Partial<MethodOption>,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = {},
|
||||||
|
TIsPage extends boolean = false
|
||||||
|
> = InstanceProperties &
|
||||||
|
InstanceMethods<TData> &
|
||||||
|
TMethod &
|
||||||
|
(TIsPage extends true ? Page.ILifetime : {}) &
|
||||||
|
TCustomInstanceProperty & {
|
||||||
|
/** 组件数据,**包括内部数据和属性值** */
|
||||||
|
data: TData & PropertyOptionToData<TProperty>
|
||||||
|
/** 组件数据,**包括内部数据和属性值**(与 `data` 一致) */
|
||||||
|
properties: TData & PropertyOptionToData<TProperty>
|
||||||
|
}
|
||||||
|
type TrivialInstance = Instance<
|
||||||
|
IAnyObject,
|
||||||
|
IAnyObject,
|
||||||
|
IAnyObject,
|
||||||
|
IAnyObject
|
||||||
|
>
|
||||||
|
type TrivialOption = Options<IAnyObject, IAnyObject, IAnyObject, IAnyObject>
|
||||||
|
type Options<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends MethodOption,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = {},
|
||||||
|
TIsPage extends boolean = false
|
||||||
|
> = Partial<Data<TData>> &
|
||||||
|
Partial<Property<TProperty>> &
|
||||||
|
Partial<Method<TMethod, TIsPage>> &
|
||||||
|
Partial<OtherOption> &
|
||||||
|
Partial<Lifetimes> &
|
||||||
|
ThisType<
|
||||||
|
Instance<
|
||||||
|
TData,
|
||||||
|
TProperty,
|
||||||
|
TMethod,
|
||||||
|
TCustomInstanceProperty,
|
||||||
|
TIsPage
|
||||||
|
>
|
||||||
|
>
|
||||||
|
interface Constructor {
|
||||||
|
<
|
||||||
|
TData extends DataOption,
|
||||||
|
TProperty extends PropertyOption,
|
||||||
|
TMethod extends MethodOption,
|
||||||
|
TCustomInstanceProperty extends IAnyObject = {},
|
||||||
|
TIsPage extends boolean = false
|
||||||
|
>(
|
||||||
|
options: Options<
|
||||||
|
TData,
|
||||||
|
TProperty,
|
||||||
|
TMethod,
|
||||||
|
TCustomInstanceProperty,
|
||||||
|
TIsPage
|
||||||
|
>
|
||||||
|
): string
|
||||||
|
}
|
||||||
|
type DataOption = Record<string, any>
|
||||||
|
type PropertyOption = Record<string, AllProperty>
|
||||||
|
type MethodOption = Record<string, Function>
|
||||||
|
|
||||||
|
interface Data<D extends DataOption> {
|
||||||
|
/** 组件的内部数据,和 `properties` 一同用于组件的模板渲染 */
|
||||||
|
data?: D
|
||||||
|
}
|
||||||
|
interface Property<P extends PropertyOption> {
|
||||||
|
/** 组件的对外属性,是属性名到属性设置的映射表 */
|
||||||
|
properties: P
|
||||||
|
}
|
||||||
|
interface Method<M extends MethodOption, TIsPage extends boolean = false> {
|
||||||
|
/** 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 [组件间通信与事件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html) */
|
||||||
|
methods: M & (TIsPage extends true ? Partial<Page.ILifetime> : {})
|
||||||
|
}
|
||||||
|
type PropertyType =
|
||||||
|
| StringConstructor
|
||||||
|
| NumberConstructor
|
||||||
|
| BooleanConstructor
|
||||||
|
| ArrayConstructor
|
||||||
|
| ObjectConstructor
|
||||||
|
| null
|
||||||
|
type ValueType<T extends PropertyType> = T extends null
|
||||||
|
? any
|
||||||
|
: T extends StringConstructor
|
||||||
|
? string
|
||||||
|
: T extends NumberConstructor
|
||||||
|
? number
|
||||||
|
: T extends BooleanConstructor
|
||||||
|
? boolean
|
||||||
|
: T extends ArrayConstructor
|
||||||
|
? any[]
|
||||||
|
: T extends ObjectConstructor
|
||||||
|
? IAnyObject
|
||||||
|
: never
|
||||||
|
type FullProperty<T extends PropertyType> = {
|
||||||
|
/** 属性类型 */
|
||||||
|
type: T
|
||||||
|
/** 属性初始值 */
|
||||||
|
value?: ValueType<T>
|
||||||
|
/** 属性值被更改时的响应函数 */
|
||||||
|
observer?:
|
||||||
|
| string
|
||||||
|
| ((
|
||||||
|
newVal: ValueType<T>,
|
||||||
|
oldVal: ValueType<T>,
|
||||||
|
changedPath: Array<string | number>
|
||||||
|
) => void)
|
||||||
|
/** 属性的类型(可以指定多个) */
|
||||||
|
optionalTypes?: ShortProperty[]
|
||||||
|
}
|
||||||
|
type AllFullProperty =
|
||||||
|
| FullProperty<StringConstructor>
|
||||||
|
| FullProperty<NumberConstructor>
|
||||||
|
| FullProperty<BooleanConstructor>
|
||||||
|
| FullProperty<ArrayConstructor>
|
||||||
|
| FullProperty<ObjectConstructor>
|
||||||
|
| FullProperty<null>
|
||||||
|
type ShortProperty =
|
||||||
|
| StringConstructor
|
||||||
|
| NumberConstructor
|
||||||
|
| BooleanConstructor
|
||||||
|
| ArrayConstructor
|
||||||
|
| ObjectConstructor
|
||||||
|
| null
|
||||||
|
type AllProperty = AllFullProperty | ShortProperty
|
||||||
|
type PropertyToData<T extends AllProperty> = T extends ShortProperty
|
||||||
|
? ValueType<T>
|
||||||
|
: FullPropertyToData<Exclude<T, ShortProperty>>
|
||||||
|
type FullPropertyToData<T extends AllFullProperty> = ValueType<T['type']>
|
||||||
|
type PropertyOptionToData<P extends PropertyOption> = {
|
||||||
|
[name in keyof P]: PropertyToData<P[name]>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InstanceProperties {
|
||||||
|
/** 组件的文件路径 */
|
||||||
|
is: string
|
||||||
|
/** 节点id */
|
||||||
|
id: string
|
||||||
|
/** 节点dataset */
|
||||||
|
dataset: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InstanceMethods<D extends DataOption> {
|
||||||
|
/** `setData` 函数用于将数据从逻辑层发送到视图层
|
||||||
|
*(异步),同时改变对应的 `this.data` 的值(同步)。
|
||||||
|
*
|
||||||
|
* **注意:**
|
||||||
|
*
|
||||||
|
* 1. **直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致**。
|
||||||
|
* 1. 仅支持设置可 JSON 化的数据。
|
||||||
|
* 1. 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
|
||||||
|
* 1. 请不要把 data 中任何一项的 value 设为 `undefined` ,否则这一项将不被设置并可能遗留一些潜在问题。
|
||||||
|
*/
|
||||||
|
setData(
|
||||||
|
/** 这次要改变的数据
|
||||||
|
*
|
||||||
|
* 以 `key: value` 的形式表示,将 `this.data` 中的 `key` 对应的值改变成 `value`。
|
||||||
|
*
|
||||||
|
* 其中 `key` 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 `array[2].message`,`a.b.c.d`,并且不需要在 this.data 中预先定义。
|
||||||
|
*/
|
||||||
|
data: Partial<D> & IAnyObject,
|
||||||
|
/** setData引起的界面更新渲染完毕后的回调函数,最低基础库: `1.5.0` */
|
||||||
|
callback?: () => void
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** 检查组件是否具有 `behavior` (检查时会递归检查被直接或间接引入的所有behavior) */
|
||||||
|
hasBehavior(behavior: Behavior.BehaviorIdentifier): void
|
||||||
|
/** 触发事件,参见组件事件 */
|
||||||
|
triggerEvent<DetailType = any>(
|
||||||
|
name: string,
|
||||||
|
detail?: DetailType,
|
||||||
|
options?: TriggerEventOption
|
||||||
|
): void
|
||||||
|
/** 创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内 */
|
||||||
|
createSelectorQuery(): SelectorQuery
|
||||||
|
/** 创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内 */
|
||||||
|
createIntersectionObserver(
|
||||||
|
options: CreateIntersectionObserverOption
|
||||||
|
): IntersectionObserver
|
||||||
|
/** 使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象(会被 `wx://component-export` 影响) */
|
||||||
|
selectComponent(selector: string): TrivialInstance
|
||||||
|
/** 使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组 */
|
||||||
|
selectAllComponents(selector: string): TrivialInstance[]
|
||||||
|
/**
|
||||||
|
* 选取当前组件节点所在的组件实例(即组件的引用者),返回它的组件实例对象(会被 `wx://component-export` 影响)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.8.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
selectOwnerComponent(): TrivialInstance
|
||||||
|
/** 获取这个关系所对应的所有关联节点,参见 组件间关系 */
|
||||||
|
getRelationNodes(relationKey: string): TrivialInstance[]
|
||||||
|
/**
|
||||||
|
* 立刻执行 callback ,其中的多个 setData 之间不会触发界面绘制(只有某些特殊场景中需要,如用于在不同组件同时 setData 时进行界面绘制同步)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.4.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
groupSetData(callback?: () => void): void
|
||||||
|
/**
|
||||||
|
* 返回当前页面的 custom-tab-bar 的组件实例
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.6.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
getTabBar(): TrivialInstance
|
||||||
|
/**
|
||||||
|
* 返回页面标识符(一个字符串),可以用来判断几个自定义组件实例是不是在同一个页面内
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.7.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
getPageId(): string
|
||||||
|
/**
|
||||||
|
* 执行关键帧动画,详见[动画](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
animate(
|
||||||
|
selector: string,
|
||||||
|
keyFrames: KeyFrame[],
|
||||||
|
duration: number,
|
||||||
|
callback?: () => void
|
||||||
|
): void
|
||||||
|
/**
|
||||||
|
* 执行关键帧动画,详见[动画](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
animate(
|
||||||
|
selector: string,
|
||||||
|
keyFrames: ScrollTimelineKeyframe[],
|
||||||
|
duration: number,
|
||||||
|
scrollTimeline: ScrollTimelineOption
|
||||||
|
): void
|
||||||
|
/**
|
||||||
|
* 清除关键帧动画,详见[动画](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
clearAnimation(selector: string, callback: () => void): void
|
||||||
|
/**
|
||||||
|
* 清除关键帧动画,详见[动画](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
**/
|
||||||
|
clearAnimation(
|
||||||
|
selector: string,
|
||||||
|
options?: ClearAnimationOptions,
|
||||||
|
callback?: () => void
|
||||||
|
): void
|
||||||
|
getOpenerEventChannel(): EventChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ComponentOptions {
|
||||||
|
/**
|
||||||
|
* [启用多slot支持](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件wxml的slot)
|
||||||
|
*/
|
||||||
|
multipleSlots?: boolean
|
||||||
|
/**
|
||||||
|
* [组件样式隔离](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件样式隔离)
|
||||||
|
*/
|
||||||
|
addGlobalClass?: boolean
|
||||||
|
/**
|
||||||
|
* [组件样式隔离](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件样式隔离)
|
||||||
|
*/
|
||||||
|
styleIsolation?:
|
||||||
|
| 'isolated'
|
||||||
|
| 'apply-shared'
|
||||||
|
| 'shared'
|
||||||
|
| 'page-isolated'
|
||||||
|
| 'page-apply-shared'
|
||||||
|
| 'page-shared'
|
||||||
|
/**
|
||||||
|
* [纯数据字段](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/pure-data.html) 是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能。从小程序基础库版本 2.8.2 开始支持。
|
||||||
|
*/
|
||||||
|
pureDataPattern?: RegExp
|
||||||
|
/**
|
||||||
|
* [虚拟化组件节点](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#%E8%99%9A%E6%8B%9F%E5%8C%96%E7%BB%84%E4%BB%B6%E8%8A%82%E7%82%B9) 使自定义组件内部的第一层节点由自定义组件本身完全决定。从小程序基础库版本 [`2.11.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) 开始支持 */
|
||||||
|
virtualHost?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TriggerEventOption {
|
||||||
|
/** 事件是否冒泡
|
||||||
|
*
|
||||||
|
* 默认值: `false`
|
||||||
|
*/
|
||||||
|
bubbles?: boolean
|
||||||
|
/** 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部
|
||||||
|
*
|
||||||
|
* 默认值: `false`
|
||||||
|
*/
|
||||||
|
composed?: boolean
|
||||||
|
/** 事件是否拥有捕获阶段
|
||||||
|
*
|
||||||
|
* 默认值: `false`
|
||||||
|
*/
|
||||||
|
capturePhase?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelationOption {
|
||||||
|
/** 目标组件的相对关系 */
|
||||||
|
type: 'parent' | 'child' | 'ancestor' | 'descendant'
|
||||||
|
/** 关系生命周期函数,当关系被建立在页面节点树中时触发,触发时机在组件attached生命周期之后 */
|
||||||
|
linked?(target: TrivialInstance): void
|
||||||
|
/** 关系生命周期函数,当关系在页面节点树中发生改变时触发,触发时机在组件moved生命周期之后 */
|
||||||
|
linkChanged?(target: TrivialInstance): void
|
||||||
|
/** 关系生命周期函数,当关系脱离页面节点树时触发,触发时机在组件detached生命周期之后 */
|
||||||
|
unlinked?(target: TrivialInstance): void
|
||||||
|
/** 如果这一项被设置,则它表示关联的目标节点所应具有的behavior,所有拥有这一behavior的组件节点都会被关联 */
|
||||||
|
target?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PageLifetimes {
|
||||||
|
/** 页面生命周期回调—监听页面显示
|
||||||
|
*
|
||||||
|
* 页面显示/切入前台时触发。
|
||||||
|
*/
|
||||||
|
show(): void
|
||||||
|
/** 页面生命周期回调—监听页面隐藏
|
||||||
|
*
|
||||||
|
* 页面隐藏/切入后台时触发。 如 `navigateTo` 或底部 `tab` 切换到其他页面,小程序切入后台等。
|
||||||
|
*/
|
||||||
|
hide(): void
|
||||||
|
/** 页面生命周期回调—监听页面尺寸变化
|
||||||
|
*
|
||||||
|
* 所在页面尺寸变化时执行
|
||||||
|
*/
|
||||||
|
resize(size: Page.IResizeOption): void
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefinitionFilter = <T extends TrivialOption>(
|
||||||
|
/** 使用该 behavior 的 component/behavior 的定义对象 */
|
||||||
|
defFields: T,
|
||||||
|
/** 该 behavior 所使用的 behavior 的 definitionFilter 函数列表 */
|
||||||
|
definitionFilterArr?: DefinitionFilter[]
|
||||||
|
) => void
|
||||||
|
|
||||||
|
interface Lifetimes {
|
||||||
|
/** 组件生命周期声明对象,组件的生命周期:`created`、`attached`、`ready`、`moved`、`detached` 将收归到 `lifetimes` 字段内进行声明,原有声明方式仍旧有效,如同时存在两种声明方式,则 `lifetimes` 字段内声明方式优先级最高
|
||||||
|
*
|
||||||
|
* 最低基础库: `2.2.3` */
|
||||||
|
lifetimes: Partial<{
|
||||||
|
/**
|
||||||
|
* 在组件实例刚刚被创建时执行,注意此时不能调用 `setData`
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
created(): void
|
||||||
|
/**
|
||||||
|
* 在组件实例进入页面节点树时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
attached(): void
|
||||||
|
/**
|
||||||
|
* 在组件在视图层布局完成后执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
ready(): void
|
||||||
|
/**
|
||||||
|
* 在组件实例被移动到节点树另一个位置时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
moved(): void
|
||||||
|
/**
|
||||||
|
* 在组件实例被从页面节点树移除时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
detached(): void
|
||||||
|
/**
|
||||||
|
* 每当组件方法抛出错误时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.4.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
error(err: Error): void
|
||||||
|
}>
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 在组件实例刚刚被创建时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
created(): void
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 在组件实例进入页面节点树时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
attached(): void
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 在组件在视图层布局完成后执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
ready(): void
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 在组件实例被移动到节点树另一个位置时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
moved(): void
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 在组件实例被从页面节点树移除时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
detached(): void
|
||||||
|
/**
|
||||||
|
* @deprecated 旧式的定义方式,基础库 `2.2.3` 起请在 lifetimes 中定义
|
||||||
|
*
|
||||||
|
* 每当组件方法抛出错误时执行
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.4.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
error(err: Error): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OtherOption {
|
||||||
|
/** 类似于mixins和traits的组件间代码复用机制,参见 [behaviors](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html) */
|
||||||
|
behaviors: Behavior.BehaviorIdentifier[]
|
||||||
|
/**
|
||||||
|
* 组件数据字段监听器,用于监听 properties 和 data 的变化,参见 [数据监听器](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/observer.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本:[`2.6.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
|
||||||
|
*/
|
||||||
|
observers: Record<string, (...args: any[]) => any>
|
||||||
|
/** 组件间关系定义,参见 [组件间关系](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html) */
|
||||||
|
relations: {
|
||||||
|
[componentName: string]: RelationOption
|
||||||
|
}
|
||||||
|
/** 组件接受的外部样式类,参见 [外部样式类](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html) */
|
||||||
|
externalClasses?: string[]
|
||||||
|
/** 组件所在页面的生命周期声明对象,参见 [组件生命周期](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本: [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
|
||||||
|
pageLifetimes?: Partial<PageLifetimes>
|
||||||
|
/** 一些选项(文档中介绍相关特性时会涉及具体的选项设置,这里暂不列举) */
|
||||||
|
options: ComponentOptions
|
||||||
|
|
||||||
|
/** 定义段过滤器,用于自定义组件扩展,参见 [自定义组件扩展](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/extend.html)
|
||||||
|
*
|
||||||
|
* 最低基础库版本: [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
|
||||||
|
definitionFilter?: DefinitionFilter
|
||||||
|
/**
|
||||||
|
* 组件自定义导出,当使用 `behavior: wx://component-export` 时,这个定义段可以用于指定组件被 selectComponent 调用时的返回值,参见 [组件间通信与事件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html)
|
||||||
|
* 最低基础库版本: [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
|
||||||
|
export: () => IAnyObject
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeyFrame {
|
||||||
|
/** 关键帧的偏移,范围[0-1] */
|
||||||
|
offset?: number
|
||||||
|
/** 动画缓动函数 */
|
||||||
|
ease?: string
|
||||||
|
/** 基点位置,即 CSS transform-origin */
|
||||||
|
transformOrigin?: string
|
||||||
|
/** 背景颜色,即 CSS background-color */
|
||||||
|
backgroundColor?: string
|
||||||
|
/** 底边位置,即 CSS bottom */
|
||||||
|
bottom?: number | string
|
||||||
|
/** 高度,即 CSS height */
|
||||||
|
height?: number | string
|
||||||
|
/** 左边位置,即 CSS left */
|
||||||
|
left?: number | string
|
||||||
|
/** 宽度,即 CSS width */
|
||||||
|
width?: number | string
|
||||||
|
/** 不透明度,即 CSS opacity */
|
||||||
|
opacity?: number | string
|
||||||
|
/** 右边位置,即 CSS right */
|
||||||
|
right?: number | string
|
||||||
|
/** 顶边位置,即 CSS top */
|
||||||
|
top?: number | string
|
||||||
|
/** 变换矩阵,即 CSS transform matrix */
|
||||||
|
matrix?: number[]
|
||||||
|
/** 三维变换矩阵,即 CSS transform matrix3d */
|
||||||
|
matrix3d?: number[]
|
||||||
|
/** 旋转,即 CSS transform rotate */
|
||||||
|
rotate?: number
|
||||||
|
/** 三维旋转,即 CSS transform rotate3d */
|
||||||
|
rotate3d?: number[]
|
||||||
|
/** X 方向旋转,即 CSS transform rotateX */
|
||||||
|
rotateX?: number
|
||||||
|
/** Y 方向旋转,即 CSS transform rotateY */
|
||||||
|
rotateY?: number
|
||||||
|
/** Z 方向旋转,即 CSS transform rotateZ */
|
||||||
|
rotateZ?: number
|
||||||
|
/** 缩放,即 CSS transform scale */
|
||||||
|
scale?: number[]
|
||||||
|
/** 三维缩放,即 CSS transform scale3d */
|
||||||
|
scale3d?: number[]
|
||||||
|
/** X 方向缩放,即 CSS transform scaleX */
|
||||||
|
scaleX?: number
|
||||||
|
/** Y 方向缩放,即 CSS transform scaleY */
|
||||||
|
scaleY?: number
|
||||||
|
/** Z 方向缩放,即 CSS transform scaleZ */
|
||||||
|
scaleZ?: number
|
||||||
|
/** 倾斜,即 CSS transform skew */
|
||||||
|
skew?: number[]
|
||||||
|
/** X 方向倾斜,即 CSS transform skewX */
|
||||||
|
skewX?: number
|
||||||
|
/** Y 方向倾斜,即 CSS transform skewY */
|
||||||
|
skewY?: number
|
||||||
|
/** 位移,即 CSS transform translate */
|
||||||
|
translate?: Array<number | string>
|
||||||
|
/** 三维位移,即 CSS transform translate3d */
|
||||||
|
translate3d?: Array<number | string>
|
||||||
|
/** X 方向位移,即 CSS transform translateX */
|
||||||
|
translateX?: number | string
|
||||||
|
/** Y 方向位移,即 CSS transform translateY */
|
||||||
|
translateY?: number | string
|
||||||
|
/** Z 方向位移,即 CSS transform translateZ */
|
||||||
|
translateZ?: number | string
|
||||||
|
}
|
||||||
|
interface ClearAnimationOptions {
|
||||||
|
/** 基点位置,即 CSS transform-origin */
|
||||||
|
transformOrigin?: boolean
|
||||||
|
/** 背景颜色,即 CSS background-color */
|
||||||
|
backgroundColor?: boolean
|
||||||
|
/** 底边位置,即 CSS bottom */
|
||||||
|
bottom?: boolean
|
||||||
|
/** 高度,即 CSS height */
|
||||||
|
height?: boolean
|
||||||
|
/** 左边位置,即 CSS left */
|
||||||
|
left?: boolean
|
||||||
|
/** 宽度,即 CSS width */
|
||||||
|
width?: boolean
|
||||||
|
/** 不透明度,即 CSS opacity */
|
||||||
|
opacity?: boolean
|
||||||
|
/** 右边位置,即 CSS right */
|
||||||
|
right?: boolean
|
||||||
|
/** 顶边位置,即 CSS top */
|
||||||
|
top?: boolean
|
||||||
|
/** 变换矩阵,即 CSS transform matrix */
|
||||||
|
matrix?: boolean
|
||||||
|
/** 三维变换矩阵,即 CSS transform matrix3d */
|
||||||
|
matrix3d?: boolean
|
||||||
|
/** 旋转,即 CSS transform rotate */
|
||||||
|
rotate?: boolean
|
||||||
|
/** 三维旋转,即 CSS transform rotate3d */
|
||||||
|
rotate3d?: boolean
|
||||||
|
/** X 方向旋转,即 CSS transform rotateX */
|
||||||
|
rotateX?: boolean
|
||||||
|
/** Y 方向旋转,即 CSS transform rotateY */
|
||||||
|
rotateY?: boolean
|
||||||
|
/** Z 方向旋转,即 CSS transform rotateZ */
|
||||||
|
rotateZ?: boolean
|
||||||
|
/** 缩放,即 CSS transform scale */
|
||||||
|
scale?: boolean
|
||||||
|
/** 三维缩放,即 CSS transform scale3d */
|
||||||
|
scale3d?: boolean
|
||||||
|
/** X 方向缩放,即 CSS transform scaleX */
|
||||||
|
scaleX?: boolean
|
||||||
|
/** Y 方向缩放,即 CSS transform scaleY */
|
||||||
|
scaleY?: boolean
|
||||||
|
/** Z 方向缩放,即 CSS transform scaleZ */
|
||||||
|
scaleZ?: boolean
|
||||||
|
/** 倾斜,即 CSS transform skew */
|
||||||
|
skew?: boolean
|
||||||
|
/** X 方向倾斜,即 CSS transform skewX */
|
||||||
|
skewX?: boolean
|
||||||
|
/** Y 方向倾斜,即 CSS transform skewY */
|
||||||
|
skewY?: boolean
|
||||||
|
/** 位移,即 CSS transform translate */
|
||||||
|
translate?: boolean
|
||||||
|
/** 三维位移,即 CSS transform translate3d */
|
||||||
|
translate3d?: boolean
|
||||||
|
/** X 方向位移,即 CSS transform translateX */
|
||||||
|
translateX?: boolean
|
||||||
|
/** Y 方向位移,即 CSS transform translateY */
|
||||||
|
translateY?: boolean
|
||||||
|
/** Z 方向位移,即 CSS transform translateZ */
|
||||||
|
translateZ?: boolean
|
||||||
|
}
|
||||||
|
interface ScrollTimelineKeyframe {
|
||||||
|
composite?: 'replace' | 'add' | 'accumulate' | 'auto'
|
||||||
|
easing?: string
|
||||||
|
offset?: number | null
|
||||||
|
[property: string]: string | number | null | undefined
|
||||||
|
}
|
||||||
|
interface ScrollTimelineOption {
|
||||||
|
/** 指定滚动元素的选择器(只支持 scroll-view),该元素滚动时会驱动动画的进度 */
|
||||||
|
scrollSource: string
|
||||||
|
/** 指定滚动的方向。有效值为 horizontal 或 vertical */
|
||||||
|
orientation?: string
|
||||||
|
/** 指定开始驱动动画进度的滚动偏移量,单位 px */
|
||||||
|
startScrollOffset: number
|
||||||
|
/** 指定停止驱动动画进度的滚动偏移量,单位 px */
|
||||||
|
endScrollOffset: number
|
||||||
|
/** 起始和结束的滚动范围映射的时间长度,该时间可用于与关键帧动画里的时间 (duration) 相匹配,单位 ms */
|
||||||
|
timeRange: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Component构造器可用于定义组件,调用Component构造器时可以指定组件的属性、数据、方法等。
|
||||||
|
*
|
||||||
|
* * 使用 `this.data` 可以获取内部数据和属性值,但不要直接修改它们,应使用 `setData` 修改。
|
||||||
|
* * 生命周期函数无法在组件方法中通过 `this` 访问到。
|
||||||
|
* * 属性名应避免以 data 开头,即不要命名成 `dataXyz` 这样的形式,因为在 WXML 中, `data-xyz=""` 会被作为节点 dataset 来处理,而不是组件属性。
|
||||||
|
* * 在一个组件的定义和使用时,组件的属性名和 data 字段相互间都不能冲突(尽管它们位于不同的定义段中)。
|
||||||
|
* * 从基础库 `2.0.9` 开始,对象类型的属性和 data 字段中可以包含函数类型的子字段,即可以通过对象类型的属性字段来传递函数。低于这一版本的基础库不支持这一特性。
|
||||||
|
* * `bug` : 对于 type 为 Object 或 Array 的属性,如果通过该组件自身的 `this.setData` 来改变属性值的一个子字段,则依旧会触发属性 observer ,且 observer 接收到的 `newVal` 是变化的那个子字段的值, `oldVal` 为空, `changedPath` 包含子字段的字段名相关信息。
|
||||||
|
*/
|
||||||
|
declare let Component: WechatMiniprogram.Component.Constructor
|
||||||
1435
frontend_miniprogram/typings/types/wx/lib.wx.event.d.ts
vendored
Normal file
259
frontend_miniprogram/typings/types/wx/lib.wx.page.d.ts
vendored
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
/*! *****************************************************************************
|
||||||
|
Copyright (c) 2021 Tencent, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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 without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
***************************************************************************** */
|
||||||
|
|
||||||
|
declare namespace WechatMiniprogram.Page {
|
||||||
|
type Instance<
|
||||||
|
TData extends DataOption,
|
||||||
|
TCustom extends CustomOption
|
||||||
|
> = OptionalInterface<ILifetime> &
|
||||||
|
InstanceProperties &
|
||||||
|
InstanceMethods<TData> &
|
||||||
|
Data<TData> &
|
||||||
|
TCustom
|
||||||
|
type Options<
|
||||||
|
TData extends DataOption,
|
||||||
|
TCustom extends CustomOption
|
||||||
|
> = (TCustom & Partial<Data<TData>> & Partial<ILifetime>) &
|
||||||
|
ThisType<Instance<TData, TCustom>>
|
||||||
|
type TrivialInstance = Instance<IAnyObject, IAnyObject>
|
||||||
|
interface Constructor {
|
||||||
|
<TData extends DataOption, TCustom extends CustomOption>(
|
||||||
|
options: Options<TData, TCustom>
|
||||||
|
): void
|
||||||
|
}
|
||||||
|
interface ILifetime {
|
||||||
|
/** 生命周期回调—监听页面加载
|
||||||
|
*
|
||||||
|
* 页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
|
||||||
|
*/
|
||||||
|
onLoad(
|
||||||
|
/** 打开当前页面路径中的参数 */
|
||||||
|
query: Record<string, string | undefined>
|
||||||
|
): void | Promise<void>
|
||||||
|
/** 生命周期回调—监听页面显示
|
||||||
|
*
|
||||||
|
* 页面显示/切入前台时触发。
|
||||||
|
*/
|
||||||
|
onShow(): void | Promise<void>
|
||||||
|
/** 生命周期回调—监听页面初次渲染完成
|
||||||
|
*
|
||||||
|
* 页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。
|
||||||
|
*
|
||||||
|
|
||||||
|
* 注意:对界面内容进行设置的 API 如`wx.setNavigationBarTitle`,请在`onReady`之后进行。
|
||||||
|
*/
|
||||||
|
onReady(): void | Promise<void>
|
||||||
|
/** 生命周期回调—监听页面隐藏
|
||||||
|
*
|
||||||
|
* 页面隐藏/切入后台时触发。 如 `navigateTo` 或底部 `tab` 切换到其他页面,小程序切入后台等。
|
||||||
|
*/
|
||||||
|
onHide(): void | Promise<void>
|
||||||
|
/** 生命周期回调—监听页面卸载
|
||||||
|
*
|
||||||
|
* 页面卸载时触发。如`redirectTo`或`navigateBack`到其他页面时。
|
||||||
|
*/
|
||||||
|
onUnload(): void | Promise<void>
|
||||||
|
/** 监听用户下拉动作
|
||||||
|
*
|
||||||
|
* 监听用户下拉刷新事件。
|
||||||
|
* - 需要在`app.json`的`window`选项中或页面配置中开启`enablePullDownRefresh`。
|
||||||
|
* - 可以通过`wx.startPullDownRefresh`触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
|
||||||
|
* - 当处理完数据刷新后,`wx.stopPullDownRefresh`可以停止当前页面的下拉刷新。
|
||||||
|
*/
|
||||||
|
onPullDownRefresh(): void | Promise<void>
|
||||||
|
/** 页面上拉触底事件的处理函数
|
||||||
|
*
|
||||||
|
* 监听用户上拉触底事件。
|
||||||
|
* - 可以在`app.json`的`window`选项中或页面配置中设置触发距离`onReachBottomDistance`。
|
||||||
|
* - 在触发距离内滑动期间,本事件只会被触发一次。
|
||||||
|
*/
|
||||||
|
onReachBottom(): void | Promise<void>
|
||||||
|
/** 用户点击右上角转发
|
||||||
|
*
|
||||||
|
* 监听用户点击页面内转发按钮(`<button>` 组件 `open-type="share"`)或右上角菜单“转发”按钮的行为,并自定义转发内容。
|
||||||
|
*
|
||||||
|
* **注意:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮**
|
||||||
|
*
|
||||||
|
* 此事件需要 return 一个 Object,用于自定义转发内容
|
||||||
|
*/
|
||||||
|
onShareAppMessage(
|
||||||
|
/** 分享发起来源参数 */
|
||||||
|
options: IShareAppMessageOption
|
||||||
|
): ICustomShareContent | void
|
||||||
|
/**
|
||||||
|
* 监听右上角菜单“分享到朋友圈”按钮的行为,并自定义分享内容
|
||||||
|
*
|
||||||
|
* 本接口为 Beta 版本,暂只在 Android 平台支持,详见 [分享到朋友圈 (Beta)](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html)
|
||||||
|
*
|
||||||
|
* 基础库 2.11.3 开始支持,低版本需做兼容处理。
|
||||||
|
*/
|
||||||
|
onShareTimeline(): ICustomTimelineContent | void
|
||||||
|
|
||||||
|
/** 页面滚动触发事件的处理函数
|
||||||
|
*
|
||||||
|
* 监听用户滑动页面事件。
|
||||||
|
*/
|
||||||
|
onPageScroll(
|
||||||
|
/** 页面滚动参数 */
|
||||||
|
options: IPageScrollOption
|
||||||
|
): void | Promise<void>
|
||||||
|
|
||||||
|
/** 当前是 tab 页时,点击 tab 时触发,最低基础库: `1.9.0` */
|
||||||
|
onTabItemTap(
|
||||||
|
/** tab 点击参数 */
|
||||||
|
options: ITabItemTapOption
|
||||||
|
): void | Promise<void>
|
||||||
|
|
||||||
|
/** 窗口尺寸改变时触发,最低基础库:`2.4.0` */
|
||||||
|
onResize(
|
||||||
|
/** 窗口尺寸参数 */
|
||||||
|
options: IResizeOption
|
||||||
|
): void | Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听用户点击右上角菜单“收藏”按钮的行为,并自定义收藏内容。
|
||||||
|
* 基础库 2.10.3,安卓 7.0.15 版本起支持,iOS 暂不支持
|
||||||
|
*/
|
||||||
|
onAddToFavorites(options: IAddToFavoritesOption): IAddToFavoritesContent
|
||||||
|
}
|
||||||
|
interface InstanceProperties {
|
||||||
|
/** 页面的文件路径 */
|
||||||
|
is: string
|
||||||
|
|
||||||
|
/** 到当前页面的路径 */
|
||||||
|
route: string
|
||||||
|
|
||||||
|
/** 打开当前页面路径中的参数 */
|
||||||
|
options: Record<string, string | undefined>
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataOption = Record<string, any>
|
||||||
|
type CustomOption = Record<string, any>
|
||||||
|
|
||||||
|
type InstanceMethods<D extends DataOption> = Component.InstanceMethods<D>
|
||||||
|
|
||||||
|
interface Data<D extends DataOption> {
|
||||||
|
/** 页面的初始数据
|
||||||
|
*
|
||||||
|
* `data` 是页面第一次渲染使用的**初始数据**。
|
||||||
|
*
|
||||||
|
* 页面加载时,`data` 将会以`JSON`字符串的形式由逻辑层传至渲染层,因此`data`中的数据必须是可以转成`JSON`的类型:字符串,数字,布尔值,对象,数组。
|
||||||
|
*
|
||||||
|
* 渲染层可以通过 `WXML` 对数据进行绑定。
|
||||||
|
*/
|
||||||
|
data: D
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICustomShareContent {
|
||||||
|
/** 转发标题。默认值:当前小程序名称 */
|
||||||
|
title?: string
|
||||||
|
/** 转发路径,必须是以 / 开头的完整路径。默认值:当前页面 path */
|
||||||
|
path?: string
|
||||||
|
/** 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4,最低基础库: `1.5.0`。默认值:使用默认截图 */
|
||||||
|
imageUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ICustomTimelineContent {
|
||||||
|
/** 自定义标题,即朋友圈列表页上显示的标题。默认值:当前小程序名称 */
|
||||||
|
title?: string
|
||||||
|
/** 自定义页面路径中携带的参数,如 `path?a=1&b=2` 的 “?” 后面部分 默认值:当前页面路径携带的参数 */
|
||||||
|
query?: string
|
||||||
|
/** 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持 PNG 及 JPG。显示图片长宽比是 1:1。默认值:默认使用小程序 Logo*/
|
||||||
|
imageUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPageScrollOption {
|
||||||
|
/** 页面在垂直方向已滚动的距离(单位px) */
|
||||||
|
scrollTop: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IShareAppMessageOption {
|
||||||
|
/** 转发事件来源。
|
||||||
|
*
|
||||||
|
* 可选值:
|
||||||
|
* - `button`:页面内转发按钮;
|
||||||
|
* - `menu`:右上角转发菜单。
|
||||||
|
*
|
||||||
|
* 最低基础库: `1.2.4`
|
||||||
|
*/
|
||||||
|
from: 'button' | 'menu' | string
|
||||||
|
/** 如果 `from` 值是 `button`,则 `target` 是触发这次转发事件的 `button`,否则为 `undefined`
|
||||||
|
*
|
||||||
|
* 最低基础库: `1.2.4` */
|
||||||
|
target: any
|
||||||
|
/** 页面中包含`<web-view>`组件时,返回当前`<web-view>`的url
|
||||||
|
*
|
||||||
|
* 最低基础库: `1.6.4`
|
||||||
|
*/
|
||||||
|
webViewUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITabItemTapOption {
|
||||||
|
/** 被点击tabItem的序号,从0开始,最低基础库: `1.9.0` */
|
||||||
|
index: string
|
||||||
|
/** 被点击tabItem的页面路径,最低基础库: `1.9.0` */
|
||||||
|
pagePath: string
|
||||||
|
/** 被点击tabItem的按钮文字,最低基础库: `1.9.0` */
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IResizeOption {
|
||||||
|
size: {
|
||||||
|
/** 变化后的窗口宽度,单位 px */
|
||||||
|
windowWidth: number
|
||||||
|
/** 变化后的窗口高度,单位 px */
|
||||||
|
windowHeight: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAddToFavoritesOption {
|
||||||
|
/** 页面中包含web-view组件时,返回当前web-view的url */
|
||||||
|
webviewUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAddToFavoritesContent {
|
||||||
|
/** 自定义标题,默认值:页面标题或账号名称 */
|
||||||
|
title?: string
|
||||||
|
/** 自定义图片,显示图片长宽比为 1:1,默认值:页面截图 */
|
||||||
|
imageUrl?: string
|
||||||
|
/** 自定义query字段,默认值:当前页面的query */
|
||||||
|
query?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetCurrentPages {
|
||||||
|
(): Array<Instance<IAnyObject, IAnyObject>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册小程序中的一个页面。接受一个 `Object` 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
|
||||||
|
*/
|
||||||
|
declare let Page: WechatMiniprogram.Page.Constructor
|
||||||
|
/**
|
||||||
|
* 获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。
|
||||||
|
|
||||||
|
* __注意:__
|
||||||
|
|
||||||
|
* - __不要尝试修改页面栈,会导致路由以及页面状态错误。__
|
||||||
|
* - 不要在 `App.onLaunch` 的时候调用 `getCurrentPages()`,此时 `page` 还没有生成。
|
||||||
|
*/
|
||||||
|
declare let getCurrentPages: WechatMiniprogram.Page.GetCurrentPages
|
||||||