@ -0,0 +1,77 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/login/login",
|
||||
"pages/search/search",
|
||||
"pages/publish/publish",
|
||||
"pages/detail/detail",
|
||||
"pages/message/message",
|
||||
"pages/user/user",
|
||||
"pages/claim/claim",
|
||||
"pages/match/match",
|
||||
"pages/about/about",
|
||||
"pages/settings/settings",
|
||||
"pages/privacy/privacy",
|
||||
"pages/agreement/agreement",
|
||||
"pages/webview/webview"
|
||||
],
|
||||
"window": {
|
||||
"backgroundTextStyle": "light",
|
||||
"navigationBarBackgroundColor": "#2196F3",
|
||||
"navigationBarTitleText": "失物招领",
|
||||
"navigationBarTextStyle": "white"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#999999",
|
||||
"selectedColor": "#2196F3",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页",
|
||||
"iconPath": "images/home_new.png",
|
||||
"selectedIconPath": "images/home_selected_new.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/search/search",
|
||||
"text": "搜索",
|
||||
"iconPath": "images/search_new.png",
|
||||
"selectedIconPath": "images/search_selected_new.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/publish/publish",
|
||||
"text": "发布",
|
||||
"iconPath": "images/publish_new.png",
|
||||
"selectedIconPath": "images/publish_selected_new.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/message/message",
|
||||
"text": "消息",
|
||||
"iconPath": "images/message_new.png",
|
||||
"selectedIconPath": "images/message_selected_new.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/user/user",
|
||||
"text": "我的",
|
||||
"iconPath": "images/user_new.png",
|
||||
"selectedIconPath": "images/user_selected_new.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sitemapLocation": "sitemap.json",
|
||||
"permission": {
|
||||
"scope.userInfo": {
|
||||
"desc": "您的信息将用于完善用户资料"
|
||||
},
|
||||
"scope.camera": {
|
||||
"desc": "用于拍照上传物品图片"
|
||||
},
|
||||
"scope.writePhotosAlbum": {
|
||||
"desc": "用于保存图片"
|
||||
}
|
||||
},
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation",
|
||||
"chooseLocation"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,216 @@
|
||||
/**app.wxss**/
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 页面标题样式 */
|
||||
.page-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 搜索框样式 */
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 36px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 18px;
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-button {
|
||||
margin-left: 10px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-color: #2196F3;
|
||||
border-radius: 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 物品列表样式 */
|
||||
.item-list {
|
||||
padding: 0 15px 20px;
|
||||
}
|
||||
|
||||
.item-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
border-radius: 22px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background-color: #fff;
|
||||
color: #2196F3;
|
||||
border: 1px solid #2196F3;
|
||||
border-radius: 22px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 表单样式 */
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 图片上传样式 */
|
||||
.image-upload {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.image-item {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.image-upload-btn {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 1px dashed #ddd;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 消息提示样式 */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* 加载动画样式 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 0;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"permissions": {
|
||||
"openapi": []
|
||||
},
|
||||
"timeout": 60,
|
||||
"memorySize": 512
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "imageSearch",
|
||||
"version": "1.0.0",
|
||||
"description": "图片搜索云函数",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"wx-server-sdk": "~2.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "login",
|
||||
"version": "1.0.0",
|
||||
"description": "用户登录云函数",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"wx-server-sdk": "~2.11.0"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"permissions": {
|
||||
"openapi": []
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "tencentAI",
|
||||
"version": "1.0.0",
|
||||
"description": "腾讯云图像识别云函数",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"image-size": "^1.0.2",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"wx-server-sdk": "~2.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 351 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 399 B |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 298 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 305 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 266 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 970 B |
|
After Width: | Height: | Size: 464 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 250 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 984 B |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 276 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 220 B |
@ -0,0 +1,78 @@
|
||||
<!-- pages/about/about.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<text class="title">关于我们</text>
|
||||
</view>
|
||||
|
||||
<!-- 应用信息 -->
|
||||
<view class="app-info">
|
||||
<image class="app-logo" src="/images/app_logo.png" mode="aspectFit"></image>
|
||||
<text class="app-name">{{appInfo.name}}</text>
|
||||
<text class="app-version">版本 {{appInfo.version}}</text>
|
||||
<text class="app-description">{{appInfo.description}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 功能介绍 -->
|
||||
<view class="feature-section">
|
||||
<view class="section-title">功能介绍</view>
|
||||
<view class="feature-list">
|
||||
<view class="feature-item">
|
||||
<image class="feature-icon" src="/images/lost.png" mode="aspectFit"></image>
|
||||
<text class="feature-text">发布失物信息</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<image class="feature-icon" src="/images/found.png" mode="aspectFit"></image>
|
||||
<text class="feature-text">发布招领信息</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<image class="feature-icon" src="/images/search.png" mode="aspectFit"></image>
|
||||
<text class="feature-text">搜索物品信息</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<image class="feature-icon" src="/images/match.svg" mode="aspectFit"></image>
|
||||
<text class="feature-text">智能匹配物品</text>
|
||||
</view>
|
||||
<view class="feature-item">
|
||||
<image class="feature-icon" src="/images/message.svg" mode="aspectFit"></image>
|
||||
<text class="feature-text">消息通知提醒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<view class="contact-section">
|
||||
<view class="section-title">联系我们</view>
|
||||
<view class="contact-list">
|
||||
<view class="contact-item" bindtap="openWebsite">
|
||||
<image class="contact-icon" src="/images/website.png" mode="aspectFit"></image>
|
||||
<text class="contact-text">官方网站</text>
|
||||
<text class="arrow">→</text>
|
||||
</view>
|
||||
<view class="contact-item" bindtap="contactUs">
|
||||
<image class="contact-icon" src="/images/email.png" mode="aspectFit"></image>
|
||||
<text class="contact-text">{{appInfo.contactEmail}}</text>
|
||||
<text class="arrow">→</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<image class="contact-icon" src="/images/developer.png" mode="aspectFit"></image>
|
||||
<text class="contact-text">{{appInfo.developer}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 更新日志 -->
|
||||
<view class="update-section">
|
||||
<view class="section-title">更新日志</view>
|
||||
<view class="update-list">
|
||||
<view class="update-item" wx:for="{{appInfo.updateLog}}" wx:key="index">
|
||||
<text class="update-text">{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 检查更新 -->
|
||||
<view class="update-button-section">
|
||||
<button class="check-update-btn" type="primary" bindtap="checkUpdate">检查更新</button>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,174 @@
|
||||
/* pages/about/about.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 应用信息 */
|
||||
.app-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 50rpx 0;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.app-version {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.app-description {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
padding: 0 60rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
/* 功能介绍 */
|
||||
.feature-section {
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 20rpx 30rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 33.33%;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 联系信息 */
|
||||
.contact-section {
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.contact-list {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.contact-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.contact-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.contact-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 28rpx;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* 更新日志 */
|
||||
.update-section {
|
||||
background-color: #fff;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.update-list {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.update-item {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.update-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.update-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
/* 检查更新按钮 */
|
||||
.update-button-section {
|
||||
padding: 0 30rpx 30rpx;
|
||||
}
|
||||
|
||||
.check-update-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
font-size: 28rpx;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<!-- pages/agreement/agreement.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<text class="title">用户协议</text>
|
||||
</view>
|
||||
|
||||
<!-- 用户协议内容 -->
|
||||
<scroll-view class="content" scroll-y>
|
||||
<view class="agreement-content">
|
||||
<text class="content-text">
|
||||
{{agreementContent}}
|
||||
</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,46 @@
|
||||
/* pages/agreement/agreement.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.agreement-content {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
color: #333;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/* 添加段落间距 */
|
||||
.content-text text {
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
// pages/claim/claim.js
|
||||
Page({
|
||||
data: {
|
||||
claimRequests: [], // 认领请求列表
|
||||
loading: true, // 是否正在加载
|
||||
hasMore: true, // 是否还有更多请求
|
||||
pageNum: 1, // 当前页码
|
||||
itemType: 'all' // 物品类型,'all'全部,'lost'失物,'found'招领
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
// 检查用户是否已登录
|
||||
this.checkLoginStatus();
|
||||
|
||||
// 加载认领请求列表
|
||||
this.loadClaimRequests();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus: function() {
|
||||
const app = getApp();
|
||||
if (!app.globalData.hasUserInfo) {
|
||||
// 用户未登录,跳转到登录页面
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 切换物品类型
|
||||
switchItemType: function(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
this.setData({
|
||||
itemType: type,
|
||||
pageNum: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadClaimRequests();
|
||||
},
|
||||
|
||||
// 加载认领请求列表
|
||||
loadClaimRequests: function() {
|
||||
if (this.data.loading || !this.data.hasMore) return;
|
||||
|
||||
this.setData({ loading: true });
|
||||
|
||||
const app = getApp();
|
||||
wx.request({
|
||||
url: app.globalData.baseUrl + '/claim/requests',
|
||||
data: {
|
||||
type: this.data.itemType,
|
||||
pageNum: this.data.pageNum,
|
||||
pageSize: 10
|
||||
},
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data && res.data.requests) {
|
||||
const newRequests = res.data.requests;
|
||||
|
||||
// 如果是第一页,直接替换数据;否则追加数据
|
||||
if (this.data.pageNum === 1) {
|
||||
this.setData({
|
||||
claimRequests: newRequests,
|
||||
pageNum: 2,
|
||||
hasMore: newRequests.length === 10
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
claimRequests: [...this.data.claimRequests, ...newRequests],
|
||||
pageNum: this.data.pageNum + 1,
|
||||
hasMore: newRequests.length === 10
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('加载认领请求失败', err);
|
||||
wx.showToast({
|
||||
title: '加载失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
complete: () => {
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 加载更多认领请求
|
||||
onReachBottom: function() {
|
||||
this.loadClaimRequests();
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh: function() {
|
||||
this.setData({
|
||||
pageNum: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadClaimRequests();
|
||||
},
|
||||
|
||||
// 跳转到物品详情页
|
||||
goToDetail: function(e) {
|
||||
const itemId = e.currentTarget.dataset.id;
|
||||
const type = e.currentTarget.dataset.type;
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/detail/detail?id=${itemId}&type=${type}`
|
||||
});
|
||||
},
|
||||
|
||||
// 查看认领人信息
|
||||
viewClaimUserInfo: function(e) {
|
||||
const { userId } = e.currentTarget.dataset;
|
||||
|
||||
const app = getApp();
|
||||
wx.request({
|
||||
url: app.globalData.baseUrl + `/users/${userId}`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data && res.data.user) {
|
||||
const userInfo = res.data.user;
|
||||
|
||||
wx.showModal({
|
||||
title: '认领人信息',
|
||||
content: `姓名:${userInfo.nickName}\n联系方式:${userInfo.phone}`,
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取用户信息失败', err);
|
||||
wx.showToast({
|
||||
title: '获取信息失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 同意认领
|
||||
approveClaim: function(e) {
|
||||
const { id, itemId, itemType } = e.currentTarget.dataset;
|
||||
|
||||
wx.showModal({
|
||||
title: '确认同意认领',
|
||||
content: '同意认领后,物品将标记为已认领,您可以与认领人联系确认物品归属。',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.submitClaimApproval(id, itemId, itemType, 'approve');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 拒绝认领
|
||||
rejectClaim: function(e) {
|
||||
const { id, itemId, itemType } = e.currentTarget.dataset;
|
||||
|
||||
wx.showModal({
|
||||
title: '确认拒绝认领',
|
||||
content: '拒绝认领后,该认领请求将被驳回,您可以继续等待其他认领请求。',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.submitClaimApproval(id, itemId, itemType, 'reject');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 提交认领处理结果
|
||||
submitClaimApproval: function(claimId, itemId, itemType, action) {
|
||||
wx.showLoading({
|
||||
title: '处理中...',
|
||||
});
|
||||
|
||||
const app = getApp();
|
||||
wx.request({
|
||||
url: app.globalData.baseUrl + `/claim/${claimId}/${action}`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
itemId: itemId,
|
||||
itemType: itemType
|
||||
},
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data && res.data.success) {
|
||||
// 从列表中移除该认领请求
|
||||
const newClaimRequests = this.data.claimRequests.filter(request => request.id !== claimId);
|
||||
|
||||
this.setData({
|
||||
claimRequests: newClaimRequests
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: action === 'approve' ? '已同意认领' : '已拒绝认领',
|
||||
icon: 'success'
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '处理失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('处理认领请求失败', err);
|
||||
wx.showToast({
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
complete: () => {
|
||||
wx.hideLoading();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,71 @@
|
||||
<!-- pages/claim/claim.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<text class="title">认领管理</text>
|
||||
</view>
|
||||
|
||||
<!-- 物品类型切换 -->
|
||||
<view class="item-type">
|
||||
<view class="type-tab {{itemType === 'all' ? 'active' : ''}}" data-type="all" bindtap="switchItemType">
|
||||
<text>全部</text>
|
||||
</view>
|
||||
<view class="type-tab {{itemType === 'lost' ? 'active' : ''}}" data-type="lost" bindtap="switchItemType">
|
||||
<text>失物</text>
|
||||
</view>
|
||||
<view class="type-tab {{itemType === 'found' ? 'active' : ''}}" data-type="found" bindtap="switchItemType">
|
||||
<text>招领</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 认领请求列表 -->
|
||||
<scroll-view class="claim-list" scroll-y bindscrolltolower="onReachBottom" enablePullDownRefresh="true" bindrefresh="onPullDownRefresh">
|
||||
<view class="claim-item" wx:for="{{claimRequests}}" wx:key="id">
|
||||
<!-- 认领请求基本信息 -->
|
||||
<view class="claim-header">
|
||||
<view class="claim-info">
|
||||
<text class="claim-title">来自 {{item.claimerName}} 的认领请求</text>
|
||||
<text class="claim-time">{{item.createTime}}</text>
|
||||
</view>
|
||||
<text class="claim-status" wx:if="{{item.status === 'pending'}}">待处理</text>
|
||||
<text class="claim-status approved" wx:elif="{{item.status === 'approved'}}">已同意</text>
|
||||
<text class="claim-status rejected" wx:else>已拒绝</text>
|
||||
</view>
|
||||
|
||||
<!-- 相关物品信息 -->
|
||||
<view class="related-item" data-id="{{item.itemId}}" data-type="{{item.itemType}}" bindtap="goToDetail">
|
||||
<image class="item-image" wx:if="{{item.itemImages && item.itemImages.length > 0}}" src="{{item.itemImages[0]}}" mode="aspectFill"></image>
|
||||
<view class="item-info">
|
||||
<text class="item-title">{{item.itemTitle}}</text>
|
||||
<text class="item-desc">{{item.itemDesc}}</text>
|
||||
<text class="item-type">{{item.itemType === 'lost' ? '失物' : '招领'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 认领理由 -->
|
||||
<view class="claim-reason">
|
||||
<text class="reason-label">认领理由:</text>
|
||||
<text class="reason-content">{{item.reason}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-buttons" wx:if="{{item.status === 'pending'}}">
|
||||
<button class="view-user-btn" type="default" bindtap="viewClaimUserInfo" data-user-id="{{item.claimerId}}">查看认领人信息</button>
|
||||
<button class="approve-btn" type="primary" bindtap="approveClaim" data-id="{{item.id}}" data-item-id="{{item.itemId}}" data-item-type="{{item.itemType}}">同意认领</button>
|
||||
<button class="reject-btn" type="default" bindtap="rejectClaim" data-id="{{item.id}}" data-item-id="{{item.itemId}}" data-item-type="{{item.itemType}}">拒绝认领</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty" wx:if="{{claimRequests.length === 0 && !loading}}">
|
||||
<image class="empty-icon" src="/images/no_claims.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无认领请求</text>
|
||||
<text class="empty-subtext">用户提交认领请求后,将显示在此处</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading && claimRequests.length > 0}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,254 @@
|
||||
/* pages/claim/claim.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 物品类型切换 */
|
||||
.item-type {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.type-tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
/* 认领请求列表 */
|
||||
.claim-list {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 认领请求项 */
|
||||
.claim-item {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 认领请求头部 */
|
||||
.claim-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
background-color: #f9f9f9;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.claim-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.claim-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.claim-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.claim-status {
|
||||
padding: 8rpx 20rpx;
|
||||
font-size: 24rpx;
|
||||
background-color: #ff9800;
|
||||
color: #fff;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.claim-status.approved {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.claim-status.rejected {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
/* 相关物品信息 */
|
||||
.related-item {
|
||||
display: flex;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 8rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background-color: #2196F3;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/* 认领理由 */
|
||||
.claim-reason {
|
||||
padding: 24rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.reason-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.reason-content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.view-user-btn,
|
||||
.approve-btn,
|
||||
.reject-btn {
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.view-user-btn {
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
border: 1rpx solid #ddd;
|
||||
}
|
||||
|
||||
.approve-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.reject-btn {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
border: 1rpx solid #f44336;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-subtext {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 0 60rpx;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
<!-- pages/detail/detail.wxml -->
|
||||
<view class="container">
|
||||
<!-- 图片轮播 -->
|
||||
<view class="image-carousel" wx:if="{{itemDetail}}">
|
||||
<swiper class="swiper" bindchange="onImageChange" indicator-dots="{{itemDetail.images && itemDetail.images.length > 1}}">
|
||||
<!-- 如果有图片,显示图片 -->
|
||||
<block wx:for="{{itemDetail.images}}" wx:key="index">
|
||||
<swiper-item>
|
||||
<image class="swiper-image" src="{{item}}" mode="aspectFill" bindtap="previewImage" binderror="onImageError" data-index="{{index}}"></image>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
<view class="image-count" wx:if="{{itemDetail.images && itemDetail.images.length > 1}}">{{currentImageIndex + 1}}/{{itemDetail.images.length}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 物品类型标签 -->
|
||||
<view class="item-type" wx:if="{{itemDetail}}">
|
||||
<text>{{itemType === 'lost' ? '失物信息' : '招领信息'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 认领状态标签 -->
|
||||
<view class="claim-status" wx:if="{{claimStatus === 'claimed'}}">
|
||||
<text>已被认领</text>
|
||||
</view>
|
||||
<view class="claim-status pending" wx:if="{{claimStatus === 'claiming'}}">
|
||||
<text>认领审核中</text>
|
||||
</view>
|
||||
|
||||
<!-- 物品详细信息 -->
|
||||
<view class="detail-content" wx:if="{{itemDetail}}">
|
||||
<!-- 标题 -->
|
||||
<view class="title-section">
|
||||
<text class="item-title">{{itemDetail.title}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 描述 -->
|
||||
<view class="desc-section">
|
||||
<text class="section-label">详细描述</text>
|
||||
<text class="item-desc">{{itemDetail.description}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 时间和地点 -->
|
||||
<view class="info-section">
|
||||
<text class="section-label">{{itemType === 'lost' ? '丢失' : '捡到'}}信息</text>
|
||||
<view class="info-item">
|
||||
<image class="info-icon" src="/images/match.svg"></image>
|
||||
<text class="info-text">{{itemType === 'lost' ? '丢失时间:' : '捡到时间:'}}{{itemDetail.time}}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<image class="info-icon" src="/images/match.png"></image>
|
||||
<text class="info-text">{{itemType === 'lost' ? '丢失地点:' : '捡到地点:'}}{{itemDetail.location}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人信息 -->
|
||||
<view class="contact-section">
|
||||
<text class="section-label">联系方式</text>
|
||||
<view class="contact-item">
|
||||
<image class="contact-icon" src="/images/user.png"></image>
|
||||
<text class="contact-text">{{itemDetail.contactName}}</text>
|
||||
</view>
|
||||
<view class="contact-item" bindtap="makePhoneCall">
|
||||
<image class="contact-icon" src="/images/phone.svg"></image>
|
||||
<text class="contact-text phone">{{itemDetail.contactPhone}}</text>
|
||||
<image class="copy-icon" src="/images/copy.svg" bindtap="copyPhone"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发布时间 -->
|
||||
<view class="publish-time">
|
||||
<text>发布时间:{{itemDetail.publishTime}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 删除后的空状态 -->
|
||||
<view class="empty-state" wx:if="{{!loading && !itemDetail}}">
|
||||
<image class="empty-icon" src="/images/empty.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">该物品信息已被删除</text>
|
||||
<button class="back-button" bindtap="navigateBack">返回</button>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar" wx:if="{{!loading && itemDetail}}">
|
||||
<!-- 浏览别人发布的物品时显示"我捡到了"按钮 -->
|
||||
<view class="action-buttons" wx:if="{{!isAuthor}}">
|
||||
<button class="claim-btn" type="primary" bindtap="claimItem" disabled="{{claimStatus === 'claimed'}}">
|
||||
{{claimStatus === 'claimed' ? '已被认领' : (claimStatus === 'claiming' ? '认领审核中' : '删除')}}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 自己发布的物品显示"删除"按钮 -->
|
||||
<view class="author-actions" wx:if="{{isAuthor}}">
|
||||
<button class="delete-btn" type="warn" bindtap="deleteItem">删除</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,210 @@
|
||||
/* pages/detail/detail.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 图片轮播 */
|
||||
.image-carousel {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 500rpx;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.swiper-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.image-count {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
right: 20rpx;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
/* 物品类型标签 */
|
||||
.item-type {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.item-type text {
|
||||
display: inline-block;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 认领状态标签 */
|
||||
.claim-status {
|
||||
padding: 0 30rpx 20rpx;
|
||||
}
|
||||
|
||||
.claim-status text {
|
||||
display: inline-block;
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.claim-status.pending text {
|
||||
background-color: #ff9800;
|
||||
}
|
||||
|
||||
/* 物品详细信息 */
|
||||
.detail-content {
|
||||
padding: 30rpx;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.title-section {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
/* 各信息区块 */
|
||||
.desc-section,
|
||||
.info-section,
|
||||
.contact-section {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
|
||||
/* 信息项 */
|
||||
.info-item,
|
||||
.contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.info-item:last-child,
|
||||
.contact-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-icon,
|
||||
.contact-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.info-text,
|
||||
.contact-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.contact-text.phone {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.copy-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
/* 发布时间 */
|
||||
.publish-time {
|
||||
padding: 20rpx 0;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.publish-time text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.claim-btn {
|
||||
flex: 1;
|
||||
height: 96rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
border-radius: 48rpx;
|
||||
line-height: 96rpx;
|
||||
}
|
||||
|
||||
.author-actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
flex: 1;
|
||||
height: 96rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
border-radius: 48rpx;
|
||||
line-height: 96rpx;
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
<!-- pages/index/index.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标签栏 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab {{activeTab === 'lost' ? 'active' : ''}}" data-tab="lost" bindtap="switchTab">
|
||||
<text>失物</text>
|
||||
<view class="tab-indicator {{activeTab === 'lost' ? 'show' : ''}}"></view>
|
||||
</view>
|
||||
<view class="tab {{activeTab === 'found' ? 'active' : ''}}" data-tab="found" bindtap="switchTab">
|
||||
<text>招领</text>
|
||||
<view class="tab-indicator {{activeTab === 'found' ? 'show' : ''}}"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 物品列表 -->
|
||||
<scroll-view class="item-list" scroll-y>
|
||||
<block wx:if="{{activeTab === 'lost' && lostItems.length > 0}}">
|
||||
<view class="item-card" wx:for="{{lostItems}}" wx:key="id" data-id="{{item.id}}" data-type="{{item.type}}" bindtap="goToDetail">
|
||||
<view class="item-header">
|
||||
<text class="item-title">{{item.title}}</text>
|
||||
<text class="item-status">寻找中</text>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<image class="item-image" wx:if="{{item.images && item.images.length > 0}}" src="{{item.images[0]}}" mode="aspectFill" binderror="onImageError" data-item="{{item}}"></image>
|
||||
<view class="item-info">
|
||||
<text class="item-desc">{{item.description}}</text>
|
||||
<view class="item-meta">
|
||||
<text class="item-time">{{item.lostTime}}</text>
|
||||
<text class="item-location">{{item.location}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<block wx:elif="{{activeTab === 'found' && foundItems.length > 0}}">
|
||||
<view class="item-card" wx:for="{{foundItems}}" wx:key="id" data-id="{{item.id}}" data-type="{{item.type}}" bindtap="goToDetail">
|
||||
<view class="item-header">
|
||||
<text class="item-title">{{item.title}}</text>
|
||||
<text class="item-status">待认领</text>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<image class="item-image" wx:if="{{item.images && item.images.length > 0}}" src="{{item.images[0]}}" mode="aspectFill" binderror="onImageError" data-item="{{item}}"></image>
|
||||
<view class="item-info">
|
||||
<text class="item-desc">{{item.description}}</text>
|
||||
<view class="item-meta">
|
||||
<text class="item-time">{{item.foundTime}}</text>
|
||||
<text class="item-location">{{item.location}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty" wx:if="{{(activeTab === 'lost' && lostItems.length === 0) || (activeTab === 'found' && foundItems.length === 0)}} && !loading">
|
||||
<image class="empty-icon" src="/images/empty.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">{{activeTab === 'lost' ? '暂无失物信息' : '暂无招领信息'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading && (lostItems.length > 0 || foundItems.length > 0)}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,159 @@
|
||||
/* pages/index/index.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标签栏 */
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab text {
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tab.active text {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.tab-indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 30%;
|
||||
width: 40%;
|
||||
height: 4rpx;
|
||||
background-color: #2196F3;
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.tab-indicator.show {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
/* 物品列表 */
|
||||
.item-list {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 物品卡片 */
|
||||
.item-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background-color: #2196F3;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.item-time, .item-location {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<!-- pages/login/login.wxml -->
|
||||
<view class="login-page">
|
||||
<view class="hero">
|
||||
<view class="hero-text">
|
||||
<text class="badge">AI 图片识别 · 实时通知</text>
|
||||
<text class="hero-title">失物招领 · 一键登录</text>
|
||||
<text class="hero-subtitle">连接全校同学,让物品更快回到主人身边</text>
|
||||
<view class="hero-tags">
|
||||
<view class="tag" wx:for="{{heroHighlights}}" wx:key="*this">{{item}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card login-card">
|
||||
<view class="user-preview">
|
||||
<image class="avatar" src="{{userInfo && userInfo.avatarUrl ? userInfo.avatarUrl : '/images/default_avatar.svg'}}" mode="aspectFill"></image>
|
||||
<view class="preview-text">
|
||||
<text class="welcome">{{hasUserInfo ? '欢迎回来' : '嗨,同学'}}</text>
|
||||
<text class="hint">{{hasUserInfo ? '已完成登录,可直接前往首页' : '登录后可同步发布记录、接收认领消息'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button class="primary-btn"
|
||||
bindtap="handleLogin">
|
||||
<image class="btn-icon" src="/images/user_new.png" mode="aspectFit"></image>
|
||||
<text>{{hasUserInfo ? '进入首页' : '微信一键登录'}}</text>
|
||||
</button>
|
||||
|
||||
<button class="ghost-btn" bindtap="skipLogin">暂不登录,先逛逛</button>
|
||||
</view>
|
||||
|
||||
<view class="card info-card">
|
||||
<view class="info-header">
|
||||
<text class="info-title">登录即可体验</text>
|
||||
<text class="info-desc">智能匹配、招领进度随时掌握</text>
|
||||
</view>
|
||||
<view class="benefit-list">
|
||||
<view class="benefit-item" wx:for="{{benefits}}" wx:key="title">
|
||||
<image class="benefit-icon" src="{{item.icon}}" mode="aspectFit"></image>
|
||||
<view class="benefit-text">
|
||||
<text class="benefit-title">{{item.title}}</text>
|
||||
<text class="benefit-desc">{{item.desc}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card support-card">
|
||||
<view class="support-header">
|
||||
<text class="support-title">遇到问题?联系小助手</text>
|
||||
<text class="support-desc">我们随时在线,帮你确认物品状态</text>
|
||||
</view>
|
||||
<view class="support-list">
|
||||
<view class="support-item" wx:for="{{supportChannels}}" wx:key="label">
|
||||
<view class="support-label">{{item.label}}</view>
|
||||
<text class="support-value">{{item.value}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="agreement">
|
||||
<text>登录即表示您同意</text>
|
||||
<text class="link" bindtap="showPrivacyPolicy">《隐私政策》</text>
|
||||
<text>和</text>
|
||||
<text class="link" bindtap="showUserAgreement">《用户协议》</text>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,235 @@
|
||||
/* pages/login/login.wxss */
|
||||
.login-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #eff7ff 0%, #fdfdfd 55%, #ffffff 100%);
|
||||
padding: 72rpx 48rpx 120rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32rpx;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #0078ff 0%, #00c6ff 90%);
|
||||
border-radius: 36rpx;
|
||||
padding: 56rpx;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 320rpx;
|
||||
height: 320rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
right: -80rpx;
|
||||
top: -60rpx;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 24rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 48rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.hero-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-size: 24rpx;
|
||||
padding: 8rpx 18rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 32rpx;
|
||||
padding: 48rpx;
|
||||
box-shadow: 0 20rpx 60rpx rgba(15, 85, 132, 0.08);
|
||||
}
|
||||
|
||||
.login-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32rpx;
|
||||
}
|
||||
|
||||
.user-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
background: #f2f4f7;
|
||||
border: 4rpx solid #eef3ff;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2b3d;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 26rpx;
|
||||
color: #6a7689;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
height: 100rpx;
|
||||
border-radius: 999rpx;
|
||||
background: linear-gradient(135deg, #07c160 0%, #06ad87 100%);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.primary-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.ghost-btn {
|
||||
height: 96rpx;
|
||||
border-radius: 999rpx;
|
||||
border: 2rpx solid #d6e4ff;
|
||||
color: #3977ff;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.ghost-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.info-card,
|
||||
.support-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32rpx;
|
||||
}
|
||||
|
||||
.info-header,
|
||||
.support-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.info-title,
|
||||
.support-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2b3d;
|
||||
}
|
||||
|
||||
.info-desc,
|
||||
.support-desc {
|
||||
font-size: 26rpx;
|
||||
color: #6a7689;
|
||||
}
|
||||
|
||||
.benefit-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.benefit-item {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
padding: 20rpx;
|
||||
border-radius: 24rpx;
|
||||
background: #f7fbff;
|
||||
}
|
||||
|
||||
.benefit-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.benefit-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2b3d;
|
||||
}
|
||||
|
||||
.benefit-desc {
|
||||
font-size: 26rpx;
|
||||
color: #6a7689;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.support-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
}
|
||||
|
||||
.support-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 28rpx;
|
||||
color: #1f2b3d;
|
||||
padding-bottom: 12rpx;
|
||||
border-bottom: 2rpx dashed #eef1f6;
|
||||
}
|
||||
|
||||
.support-label {
|
||||
color: #6a7689;
|
||||
}
|
||||
|
||||
.support-value {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
font-size: 24rpx;
|
||||
color: #8a94a6;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #2d6bff;
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
// pages/match/match.js
|
||||
Page({
|
||||
data: {
|
||||
matchedItems: [], // 匹配的物品列表
|
||||
loading: true, // 是否正在加载
|
||||
hasMore: true, // 是否还有更多匹配结果
|
||||
pageNum: 1, // 当前页码
|
||||
matchType: 'lost' // 匹配类型,'lost'表示匹配到的失物,'found'表示匹配到的招领
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
// 检查用户是否已登录
|
||||
this.checkLoginStatus();
|
||||
|
||||
// 加载匹配的物品列表
|
||||
this.loadMatchedItems();
|
||||
},
|
||||
|
||||
// 检查登录状态(简化版,不强制要求登录)
|
||||
checkLoginStatus: function() {
|
||||
const app = getApp();
|
||||
// 不强制要求登录,使用模拟数据继续运行
|
||||
// 如果用户未登录,我们仍然允许浏览匹配结果,只是使用默认的模拟数据
|
||||
if (!app.globalData.hasUserInfo) {
|
||||
console.log('用户未登录,使用模拟数据显示匹配结果');
|
||||
// 如果需要,可以设置一个默认的用户信息
|
||||
if (!app.globalData.userInfo) {
|
||||
app.globalData.userInfo = { nickName: '访客', avatarUrl: '/images/default_avatar.svg' };
|
||||
}
|
||||
// 确保智能匹配功能默认启用
|
||||
if (!app.globalData.settings) {
|
||||
app.globalData.settings = { enableSmartMatch: true };
|
||||
} else if (!app.globalData.settings.enableSmartMatch) {
|
||||
app.globalData.settings.enableSmartMatch = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 切换匹配类型
|
||||
switchMatchType: function(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
this.setData({
|
||||
matchType: type,
|
||||
pageNum: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadMatchedItems();
|
||||
},
|
||||
|
||||
// 加载匹配的物品列表
|
||||
loadMatchedItems: function() {
|
||||
if (this.data.loading || !this.data.hasMore) return;
|
||||
|
||||
this.setData({ loading: true });
|
||||
|
||||
const app = getApp();
|
||||
|
||||
// 检查智能匹配是否启用
|
||||
if (!app.globalData.settings || !app.globalData.settings.enableSmartMatch) {
|
||||
this.setData({
|
||||
matchedItems: [],
|
||||
loading: false,
|
||||
hasMore: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: '智能匹配功能未启用,请在设置中开启',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用本地智能匹配功能
|
||||
app.getSmartMatches(this.data.matchType, this.data.pageNum, (res) => {
|
||||
if (res.items) {
|
||||
const newItems = res.items;
|
||||
|
||||
// 如果是第一页,直接替换数据;否则追加数据
|
||||
if (this.data.pageNum === 1) {
|
||||
this.setData({
|
||||
matchedItems: newItems,
|
||||
pageNum: 2,
|
||||
hasMore: newItems.length === 10
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
matchedItems: [...this.data.matchedItems, ...newItems],
|
||||
pageNum: this.data.pageNum + 1,
|
||||
hasMore: newItems.length === 10
|
||||
});
|
||||
}
|
||||
}
|
||||
this.setData({ loading: false });
|
||||
});
|
||||
},
|
||||
|
||||
// 加载更多匹配结果
|
||||
onReachBottom: function() {
|
||||
this.loadMatchedItems();
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh: function() {
|
||||
this.setData({
|
||||
pageNum: 1,
|
||||
hasMore: true
|
||||
});
|
||||
this.loadMatchedItems();
|
||||
},
|
||||
|
||||
// 跳转到物品详情页
|
||||
goToDetail: function(e) {
|
||||
const itemId = e.currentTarget.dataset.id;
|
||||
const type = e.currentTarget.dataset.type;
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/detail/detail?id=${itemId}&type=${type}`
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到设置页面
|
||||
goToSettings: function() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/settings/settings'
|
||||
});
|
||||
},
|
||||
|
||||
// 忽略匹配
|
||||
ignoreMatch: function(e) {
|
||||
const { id, index } = e.currentTarget.dataset;
|
||||
|
||||
wx.showModal({
|
||||
title: '确认忽略',
|
||||
content: '确定要忽略这个匹配吗?忽略后将不再显示。',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.submitIgnore(id, index);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 提交忽略请求
|
||||
submitIgnore: function(id, index) {
|
||||
const app = getApp();
|
||||
|
||||
// 使用本地忽略功能
|
||||
app.ignoreMatch(id, (res) => {
|
||||
if (res.success) {
|
||||
// 从列表中移除该匹配项
|
||||
const newMatchedItems = [...this.data.matchedItems];
|
||||
newMatchedItems.splice(index, 1);
|
||||
|
||||
this.setData({
|
||||
matchedItems: newMatchedItems
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: '已忽略',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,66 @@
|
||||
<!-- pages/match/match.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<text class="title">智能匹配</text>
|
||||
<view class="settings-btn" bindtap="goToSettings">
|
||||
<image src="/images/settings.svg" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 匹配类型切换 -->
|
||||
<view class="match-type">
|
||||
<view class="type-tab {{matchType === 'lost' ? 'active' : ''}}" data-type="lost" bindtap="switchMatchType">
|
||||
<text>匹配到的失物</text>
|
||||
</view>
|
||||
<view class="type-tab {{matchType === 'found' ? 'active' : ''}}" data-type="found" bindtap="switchMatchType">
|
||||
<text>匹配到的招领</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 匹配物品列表 -->
|
||||
<scroll-view class="match-list" scroll-y>
|
||||
<view class="match-item"
|
||||
wx:for="{{matchedItems}}"
|
||||
wx:key="id"
|
||||
data-id="{{item.id}}"
|
||||
data-type="{{item.type}}"
|
||||
data-index="{{index}}">
|
||||
<!-- 匹配度提示 -->
|
||||
<view class="match-degree" style="background-color: {{item.matchDegree >= 80 ? '#4CAF50' : item.matchDegree >= 60 ? '#2196F3' : '#FF9800'}};">
|
||||
<text>匹配度:{{item.matchDegree}}%</text>
|
||||
</view>
|
||||
|
||||
<!-- 物品信息卡片 -->
|
||||
<view class="item-card" bindtap="goToDetail">
|
||||
<image class="item-image" wx:if="{{item.images && item.images.length > 0}}" src="{{item.images[0]}}" mode="aspectFill"></image>
|
||||
<view class="item-info">
|
||||
<text class="item-title">{{item.title}}</text>
|
||||
<text class="item-desc">{{item.description}}</text>
|
||||
<view class="item-meta">
|
||||
<text class="item-time">{{item.time}}</text>
|
||||
<text class="item-location">{{item.location}}</text>
|
||||
</view>
|
||||
<text class="item-type">{{item.type === 'lost' ? '失物' : '招领'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-buttons">
|
||||
<button class="ignore-btn" type="default" bindtap="ignoreMatch" data-id="{{item.id}}" data-index="{{index}}">忽略</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty" wx:if="{{matchedItems.length === 0 && !loading}}">
|
||||
<image class="empty-icon" src="/images/no_match.svg" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无匹配的物品</text>
|
||||
<text class="empty-subtext">系统会根据您发布的信息自动匹配相关物品</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading && matchedItems.length > 0}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,219 @@
|
||||
/* pages/match/match.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.settings-btn image {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
/* 匹配类型切换 */
|
||||
.match-type {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.type-tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
/* 匹配物品列表 */
|
||||
.match-list {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 匹配项 */
|
||||
.match-item {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 匹配度提示 */
|
||||
.match-degree {
|
||||
padding: 16rpx 24rpx;
|
||||
background-color: #e3f2fd;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.match-degree text {
|
||||
font-size: 24rpx;
|
||||
color: #2196F3;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 物品卡片 */
|
||||
.item-card {
|
||||
display: flex;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 8rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.item-time, .item-location {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background-color: #2196F3;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
padding: 16rpx 24rpx;
|
||||
background-color: #f9f9f9;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.ignore-btn {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
font-size: 28rpx;
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
line-height: 72rpx;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-subtext {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 0 60rpx;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
<!-- pages/message/message.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部操作栏 -->
|
||||
<view class="header">
|
||||
<text class="title">消息通知</text>
|
||||
<view class="header-actions">
|
||||
<button class="read-all-btn" size="mini" bindtap="markAllAsRead" wx:if="{{unreadCount > 0}}">一键已读</button>
|
||||
<button class="clear-all-btn" size="mini" bindtap="clearAllMessages" wx:if="{{messages.length > 0}}">清空</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息类型切换 -->
|
||||
<view class="message-type">
|
||||
<scroll-view scroll-x>
|
||||
<view class="type-tab {{messageType === 'all' ? 'active' : ''}}" data-type="all" bindtap="switchMessageType">
|
||||
<text>全部消息</text>
|
||||
<view class="badge" wx:if="{{unreadCount > 0}}">{{unreadCount}}</view>
|
||||
</view>
|
||||
<view class="type-tab {{messageType === 'unread' ? 'active' : ''}}" data-type="unread" bindtap="switchMessageType">
|
||||
<text>未读消息</text>
|
||||
<view class="badge" wx:if="{{unreadCount > 0}}">{{unreadCount}}</view>
|
||||
</view>
|
||||
<view class="type-tab {{messageType === 'system' ? 'active' : ''}}" data-type="system" bindtap="switchMessageType">
|
||||
<text>系统消息</text>
|
||||
</view>
|
||||
<view class="type-tab {{messageType === 'match' ? 'active' : ''}}" data-type="match" bindtap="switchMessageType">
|
||||
<text>匹配通知</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<scroll-view class="message-list" scroll-y>
|
||||
<view class="message-item {{item.isRead || item.status === 'read' ? '' : 'unread'}}"
|
||||
wx:for="{{messages}}"
|
||||
wx:key="id">
|
||||
<view class="message-content-wrapper"
|
||||
data-id="{{item.id}}"
|
||||
data-item-id="{{item.itemId}}"
|
||||
data-item-type="{{item.itemType}}"
|
||||
bindtap="onMessageClick">
|
||||
<view class="message-icon">
|
||||
<image src="{{item.type === 'system' ? '/images/system.svg' : (item.type === 'match' ? '/images/match.svg' : (item.type === 'claim' ? '/images/message.svg' : '/images/message.svg'))}}" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="message-content">
|
||||
<view class="message-header">
|
||||
<text class="message-title">{{item.title}}</text>
|
||||
<text class="message-time">{{item.time || '刚刚'}}</text>
|
||||
</view>
|
||||
<text class="message-desc">{{item.content}}</text>
|
||||
|
||||
<!-- 匹配物品列表(仅匹配消息显示) -->
|
||||
<view class="match-items-list" wx:if="{{item.type === 'match' && item.matchItems && item.matchItems.length > 0}}">
|
||||
<view class="match-item-card"
|
||||
wx:for="{{item.matchItems}}"
|
||||
wx:key="id"
|
||||
wx:for-item="matchItem"
|
||||
wx:for-index="idx"
|
||||
data-match-id="{{matchItem.id}}"
|
||||
data-match-type="{{matchItem.type}}"
|
||||
catchtap="onMatchItemClick">
|
||||
<image class="match-item-image"
|
||||
src="{{matchItem.images && matchItem.images.length > 0 ? matchItem.images[0] : '/images/default_item.png'}}"
|
||||
mode="aspectFill"
|
||||
binderror="onMatchImageError"
|
||||
data-index="{{idx}}"
|
||||
data-match-id="{{matchItem.id}}"></image>
|
||||
<view class="match-item-info">
|
||||
<text class="match-item-title">{{matchItem.title}}</text>
|
||||
<text class="match-item-desc" wx:if="{{matchItem.description}}">{{matchItem.description}}</text>
|
||||
<view class="match-item-meta">
|
||||
<text class="match-item-location" wx:if="{{matchItem.location}}">{{matchItem.location}}</text>
|
||||
<text class="match-item-degree">匹配度: {{matchItem.matchDegree}}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="match-items-more" wx:if="{{item.matchCount > item.matchItems.length}}">
|
||||
还有 {{item.matchCount - item.matchItems.length}} 个匹配项,点击查看全部
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="message-tags" wx:if="{{item.itemType || item.matchCount}}">
|
||||
<text class="message-tag" wx:if="{{item.itemType}}">{{item.itemType === 'lost' ? '失物' : '招领'}}</text>
|
||||
<text class="message-tag match-tag" wx:if="{{item.matchCount}}">匹配{{item.matchCount}}项</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="unread-dot" wx:if="{{!item.isRead && item.status !== 'read'}}"></view>
|
||||
</view>
|
||||
<view class="message-delete" data-id="{{item.id}}" bindtap="deleteMessage">
|
||||
<text>删除</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty" wx:if="{{messages.length === 0 && !loading}}">
|
||||
<image class="empty-icon" src="/images/no_message.svg" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无消息</text>
|
||||
<button class="test-btn" size="mini" bindtap="createTestMessage">创建测试消息</button>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading && messages.length > 0}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,311 @@
|
||||
/* pages/message/message.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部操作栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.read-all-btn {
|
||||
font-size: 24rpx;
|
||||
color: #2196F3;
|
||||
background-color: transparent;
|
||||
line-height: normal;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 消息类型切换 */
|
||||
.message-type {
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.message-type scroll-view {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
display: inline-block;
|
||||
padding: 24rpx 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.type-tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 4rpx;
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: 12rpx;
|
||||
right: 12rpx;
|
||||
min-width: 32rpx;
|
||||
height: 32rpx;
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
text-align: center;
|
||||
line-height: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
/* 消息列表 */
|
||||
.message-list {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 消息项 */
|
||||
.message-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.message-item.unread {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.message-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-right: 20rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-icon image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.message-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.message-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.message-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.message-tag {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background-color: #2196F3;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.message-tag.match-tag {
|
||||
background-color: #ff9800;
|
||||
}
|
||||
|
||||
/* 匹配物品列表 */
|
||||
.match-items-list {
|
||||
margin-top: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.match-item-card {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 16rpx;
|
||||
margin-bottom: 12rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
border: 1rpx solid #e9ecef;
|
||||
}
|
||||
|
||||
.match-item-card:active {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.match-item-image {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-right: 16rpx;
|
||||
flex-shrink: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.match-item-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.match-item-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.match-item-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 36rpx;
|
||||
margin-bottom: 8rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.match-item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.match-item-location {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.match-item-degree {
|
||||
font-size: 22rpx;
|
||||
color: #ff9800;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.match-items-more {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #2196F3;
|
||||
padding: 12rpx 0;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.unread-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
background-color: #f44336;
|
||||
border-radius: 50%;
|
||||
margin-left: 20rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.test-btn {
|
||||
margin-top: 30rpx;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
padding: 12rpx 40rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<!-- pages/privacy/privacy.wxml -->
|
||||
<view class="container">
|
||||
<!-- 顶部标题 -->
|
||||
<view class="header">
|
||||
<text class="title">隐私政策</text>
|
||||
</view>
|
||||
|
||||
<!-- 隐私政策内容 -->
|
||||
<scroll-view class="content" scroll-y>
|
||||
<view class="privacy-content">
|
||||
<text class="content-text">
|
||||
{{privacyContent}}
|
||||
</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,46 @@
|
||||
/* pages/privacy/privacy.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.privacy-content {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
color: #333;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/* 添加段落间距 */
|
||||
.content-text text {
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
/* pages/publish/publish.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 发布类型切换 */
|
||||
.publish-type {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 表单样式 */
|
||||
.publish-form {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 地点和时间选择器 */
|
||||
.location-input, .time-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.location-text, .time-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.location-placeholder, .time-placeholder {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.location-icon, .time-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 图片上传区域 */
|
||||
.image-upload {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.image-item {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.image-delete {
|
||||
position: absolute;
|
||||
top: -10rpx;
|
||||
right: -10rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.image-upload-btn {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border: 1rpx dashed #ddd;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
font-size: 64rpx;
|
||||
}
|
||||
|
||||
.image-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 提交按钮 */
|
||||
.submit-button {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
border-radius: 48rpx;
|
||||
margin-top: 40rpx;
|
||||
line-height: 96rpx;
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
<!-- pages/search/search.wxml -->
|
||||
<view class="container">
|
||||
<!-- 文字搜索框 -->
|
||||
<view class="search-bar">
|
||||
<view class="search-input-container">
|
||||
<image class="search-icon" src="/images/search.png"></image>
|
||||
<input class="search-input"
|
||||
placeholder="输入物品名称、特征等关键词"
|
||||
value="{{keyword}}"
|
||||
bindinput="onInput"
|
||||
bindconfirm="onConfirm"
|
||||
focus="{{true}}"></input>
|
||||
</view>
|
||||
<button class="search-button" type="primary" bindtap="onSearch" loading="{{loading}}">搜索</button>
|
||||
</view>
|
||||
|
||||
<!-- 搜索结果区域 -->
|
||||
<view class="results-area" wx:if="{{searchResults.length > 0}}">
|
||||
<view class="results-header">
|
||||
<text>搜索结果 ({{searchResults.length}})</text>
|
||||
</view>
|
||||
<view class="results-list">
|
||||
<view class="item-card" wx:for="{{searchResults}}" wx:key="id" data-id="{{item.id}}" data-type="{{item.type}}" bindtap="goToDetail">
|
||||
<image class="item-image" wx:if="{{item.images && item.images.length > 0}}" src="{{item.images[0]}}" mode="aspectFill" binderror="onImageError" data-index="{{index}}"></image>
|
||||
<view class="item-info">
|
||||
<text class="item-title">{{item.title}}</text>
|
||||
<text class="item-desc">{{item.description}}</text>
|
||||
<view class="item-meta">
|
||||
<text class="item-time">{{item.time}}</text>
|
||||
<text class="item-location">{{item.location}}</text>
|
||||
</view>
|
||||
<view class="item-info-bottom">
|
||||
<text class="item-type">{{item.type === 'lost' ? '失物' : '招领'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty" wx:if="{{(searchResults.length === 0 && !loading)}}">
|
||||
<image class="empty-icon" src="/images/empty.png" mode="aspectFit"></image>
|
||||
<text class="empty-text">请输入关键词进行搜索</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view class="loading" wx:if="{{loading}}">
|
||||
<text>搜索中...</text>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,312 @@
|
||||
/* pages/search/search.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 搜索类型切换 */
|
||||
.search-type {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 24rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.type-tab.active {
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 文字搜索框 */
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-input-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 72rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 30rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 搜索按钮 - 增大尺寸(统一应用于文字和图片搜索)*/
|
||||
.search-button {
|
||||
width: 200rpx;
|
||||
height: 90rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: #2196F3;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
/* 图片搜索区域 */
|
||||
.image-search-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
width: 100%;
|
||||
height: 400rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border: 2rpx dashed #ddd;
|
||||
}
|
||||
|
||||
.selected-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.upload-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.upload-hint {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.button-group .search-button {
|
||||
flex: 1;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search-hint {
|
||||
background-color: #e3f2fd;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #1976d2;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.search-progress {
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.clear-button {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
/* 搜索按钮 - 增大尺寸 */
|
||||
.search-button {
|
||||
width: 200rpx;
|
||||
height: 90rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: #2196F3;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
/* 搜索结果区域 */
|
||||
.results-area {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.results-header {
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.results-list {
|
||||
/* 结果列表样式 */
|
||||
}
|
||||
|
||||
/* 物品卡片 */
|
||||
.item-card {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 8rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.item-time, .item-location {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background-color: #2196F3;
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 16rpx;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/* 物品底部信息容器 */
|
||||
.item-info-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 8rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 相似度分数样式 */
|
||||
.similarity-score {
|
||||
font-size: 24rpx;
|
||||
color: #4CAF50;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
.loading text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
/* pages/settings/settings.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部标题 */
|
||||
.header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 设置分组 */
|
||||
.setting-section {
|
||||
margin-top: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 20rpx 30rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* 设置项 */
|
||||
.setting-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.setting-arrow {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 开关样式 */
|
||||
switch {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
/* 版本信息 */
|
||||
.version-info {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 退出登录按钮 */
|
||||
.logout-section {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
/* 最后一个设置项没有下边框 */
|
||||
.setting-section:last-child .setting-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* 云开发状态样式 */
|
||||
.cloud-status {
|
||||
font-size: 24rpx;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 4rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cloud-status.success {
|
||||
color: #4CAF50;
|
||||
background-color: #E8F5E9;
|
||||
}
|
||||
|
||||
.cloud-status.warning {
|
||||
color: #FF9800;
|
||||
background-color: #FFF3E0;
|
||||
}
|
||||
|
||||
.cloud-status.error {
|
||||
color: #F44336;
|
||||
background-color: #FFEBEE;
|
||||
}
|
||||
|
||||
.cloud-env-id {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.test-cloud-btn {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.cloud-test-result {
|
||||
padding: 20rpx 30rpx;
|
||||
margin-top: 10rpx;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.result-text {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
<view class="container">
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-info-section">
|
||||
<image class="avatar" src="{{userInfo.avatar || '/images/default_avatar.svg'}}"></image>
|
||||
<view class="user-details">
|
||||
<view class="user-name">{{userInfo.nickName || '游客用户'}}</view>
|
||||
<view class="user-id">ID: {{userInfo.openId || '未登录'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-section">
|
||||
<view class="menu-item" bindtap="navigateToSettings">
|
||||
<image class="menu-icon" src="/images/settings.svg"></image>
|
||||
<text class="menu-text">设置</text>
|
||||
<image class="menu-arrow" src="/images/website.png"></image>
|
||||
</view>
|
||||
<view class="menu-item" bindtap="navigateToMatch">
|
||||
<image class="menu-icon" src="/images/match.svg"></image>
|
||||
<text class="menu-text">智能匹配</text>
|
||||
<image class="menu-arrow" src="/images/website.png"></image>
|
||||
</view>
|
||||
<view class="menu-item" bindtap="navigateToAbout">
|
||||
<image class="menu-icon" src="/images/system.svg"></image>
|
||||
<text class="menu-text">关于我们</text>
|
||||
<image class="menu-arrow" src="/images/website.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的发布和收藏标签页 -->
|
||||
<view class="tabs">
|
||||
<view class="tab {{currentTab === 'published' ? 'active' : ''}}" bindtap="switchTab" data-tab="published">
|
||||
<text>我发布的</text>
|
||||
</view>
|
||||
<view class="tab {{currentTab === 'collections' ? 'active' : ''}}" bindtap="switchTab" data-tab="collections">
|
||||
<text>我的收藏</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我发布的物品列表 -->
|
||||
<view class="content" wx:if="{{currentTab === 'published'}}">
|
||||
<view class="item-list" wx:if="{{myItems.length > 0}}">
|
||||
<view class="item" wx:for="{{myItems}}" wx:key="id">
|
||||
<view class="item-left">
|
||||
<image class="item-image" src="{{item.images[0] || '/images/empty.png'}}"></image>
|
||||
<view class="item-info">
|
||||
<view class="item-title">
|
||||
<text class="item-type {{item.type === 'lost' ? 'lost' : 'found'}}">{{item.type === 'lost' ? '丢失' : '捡到'}}</text>
|
||||
<text>{{item.title}}</text>
|
||||
</view>
|
||||
<view class="item-location">{{item.location}}</view>
|
||||
<view class="item-time">{{item.time}}</view>
|
||||
<view class="item-status" wx:if="{{item.status === 'matched'}}">
|
||||
<text style="color: #52c41a;">✓ 已匹配</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-actions">
|
||||
<view class="action-button delete" bindtap="deleteItem" data-id="{{item.id}}" data-index="{{index}}">
|
||||
<text>删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty-state" wx:else>
|
||||
<image src="/images/empty.png"></image>
|
||||
<text>您还没有发布任何物品</text>
|
||||
<button class="publish-button" bindtap="navigateToPublish">立即发布</button>
|
||||
</view>
|
||||
<view class="loading-more" wx:if="{{hasMore && loading}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<view class="no-more" wx:if="{{!hasMore && myItems.length > 0}}">
|
||||
<text>没有更多了</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的收藏列表 -->
|
||||
<view class="content" wx:if="{{currentTab === 'collections'}}">
|
||||
<view class="item-list" wx:if="{{myCollections.length > 0}}">
|
||||
<view class="item" wx:for="{{myCollections}}" wx:key="id">
|
||||
<view class="item-left" bindtap="navigateToDetail" data-id="{{item.id}}" data-type="{{item.type}}">
|
||||
<image class="item-image" src="{{item.images[0] || '/images/empty.png'}}"></image>
|
||||
<view class="item-info">
|
||||
<view class="item-title">
|
||||
<text class="item-type {{item.type === 'lost' ? 'lost' : 'found'}}">{{item.type === 'lost' ? '丢失' : '捡到'}}</text>
|
||||
<text>{{item.title}}</text>
|
||||
</view>
|
||||
<view class="item-location">{{item.location}}</view>
|
||||
<view class="item-time">{{item.time}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-actions">
|
||||
<view class="action-button cancel" bindtap="cancelCollection" data-id="{{item.id}}" data-index="{{index}}">
|
||||
<text>取消收藏</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty-state" wx:else>
|
||||
<image src="/images/empty.png"></image>
|
||||
<text>您还没有收藏任何物品</text>
|
||||
<button class="publish-button" bindtap="navigateToHome">去首页查看</button>
|
||||
</view>
|
||||
<view class="loading-more" wx:if="{{hasMore && loading}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<view class="no-more" wx:if="{{!hasMore && myCollections.length > 0}}">
|
||||
<text>没有更多了</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,247 @@
|
||||
/* 页面容器 */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 用户信息区域 */
|
||||
.user-info-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 功能菜单 */
|
||||
.menu-section {
|
||||
background-color: #fff;
|
||||
margin-top: 16rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
width: 20rpx;
|
||||
height: 32rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* 标签页 */
|
||||
.tabs {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
margin-top: 16rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
font-size: 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #1aad19;
|
||||
}
|
||||
|
||||
.tab.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 80rpx;
|
||||
height: 4rpx;
|
||||
background-color: #1aad19;
|
||||
}
|
||||
|
||||
/* 内容区域 */
|
||||
.content {
|
||||
background-color: #fff;
|
||||
min-height: 500rpx;
|
||||
}
|
||||
|
||||
/* 物品列表 */
|
||||
.item-list {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-left {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 10rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
font-size: 20rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 10rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.item-type.lost {
|
||||
background-color: #ff6b6b;
|
||||
}
|
||||
|
||||
.item-type.found {
|
||||
background-color: #51cf66;
|
||||
}
|
||||
|
||||
.item-location {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.item-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
padding: 15rpx 30rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.action-button.delete {
|
||||
background-color: #fff1f0;
|
||||
color: #ff4d4f;
|
||||
border: 1rpx solid #ffccc7;
|
||||
}
|
||||
|
||||
.action-button.cancel {
|
||||
background-color: #f0f0f0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 0;
|
||||
}
|
||||
|
||||
.empty-state image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-state text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.publish-button {
|
||||
background-color: #1aad19;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
padding: 0 60rpx;
|
||||
line-height: 70rpx;
|
||||
border-radius: 35rpx;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-more {
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/* pages/webview/webview.wxss */
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 顶部标题栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
padding: 0 30rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
font-size: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.right-space {
|
||||
width: 88rpx;
|
||||
}
|
||||
|
||||
/* web-view组件样式 */
|
||||
.web-view {
|
||||
flex: 1;
|
||||
margin-top: 88rpx;
|
||||
height: calc(100vh - 88rpx);
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
{
|
||||
"description": "失物招领小程序",
|
||||
"packOptions": {
|
||||
"ignore": [
|
||||
{
|
||||
"value": "node_modules",
|
||||
"type": "folder"
|
||||
},
|
||||
{
|
||||
"value": ".md",
|
||||
"type": "suffix"
|
||||
},
|
||||
{
|
||||
"value": ".gitignore",
|
||||
"type": "file"
|
||||
}
|
||||
],
|
||||
"include": []
|
||||
},
|
||||
"setting": {
|
||||
"urlCheck": true,
|
||||
"es6": true,
|
||||
"enhance": true,
|
||||
"postcss": true,
|
||||
"preloadBackgroundData": false,
|
||||
"minified": true,
|
||||
"newFeature": true,
|
||||
"coverView": true,
|
||||
"nodeModules": false,
|
||||
"autoAudits": false,
|
||||
"showShadowRootInWxmlPanel": true,
|
||||
"uglifyFileName": false,
|
||||
"uploadWithSourceMap": true,
|
||||
"useIsolateContext": true,
|
||||
"userConfirmedUseMultipleSubpackages": true,
|
||||
"showES6CompileOption": false,
|
||||
"useCompilerPlugins": [
|
||||
"typescript"
|
||||
],
|
||||
"enableEngineNative": false,
|
||||
"useNativeESM": true,
|
||||
"useNewFeatureProcess": true,
|
||||
"noStatusBar": false,
|
||||
"useSignalingChannel": false,
|
||||
"removeSelectorReservedWord": true,
|
||||
"compileWorklet": false,
|
||||
"packNpmManually": false,
|
||||
"packNpmRelationList": [],
|
||||
"minifyWXSS": true,
|
||||
"minifyWXML": true,
|
||||
"localPlugins": false,
|
||||
"disableUseStrict": false,
|
||||
"condition": false,
|
||||
"swc": false,
|
||||
"disableSWC": true,
|
||||
"babelSetting": {
|
||||
"ignore": [],
|
||||
"disablePlugins": [],
|
||||
"outputPath": ""
|
||||
}
|
||||
},
|
||||
"compileType": "miniprogram",
|
||||
"cloudfunctionRoot": "cloudfunctions/",
|
||||
"libVersion": "3.10.1",
|
||||
"appid": "wx85e3844e6e547c51",
|
||||
"projectname": "shiwuzhaol",
|
||||
"isGameTourist": false,
|
||||
"simulatorType": "wechat",
|
||||
"simulatorPluginLibVersion": {},
|
||||
"condition": {
|
||||
"search": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"conversation": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"game": {
|
||||
"current": -1,
|
||||
"list": []
|
||||
},
|
||||
"miniprogram": {
|
||||
"current": 0,
|
||||
"list": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "首页",
|
||||
"pathName": "pages/index/index",
|
||||
"query": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"editorSetting": {}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"libVersion": "3.10.1",
|
||||
"projectname": "sw",
|
||||
"condition": {},
|
||||
"setting": {
|
||||
"urlCheck": true,
|
||||
"coverView": true,
|
||||
"lazyloadPlaceholderEnable": false,
|
||||
"skylineRenderEnable": false,
|
||||
"preloadBackgroundData": false,
|
||||
"autoAudits": false,
|
||||
"useApiHook": true,
|
||||
"useApiHostProcess": true,
|
||||
"showShadowRootInWxmlPanel": true,
|
||||
"useStaticServer": false,
|
||||
"useLanDebug": false,
|
||||
"showES6CompileOption": false,
|
||||
"compileHotReLoad": true,
|
||||
"checkInvalidKey": true,
|
||||
"ignoreDevUnusedFiles": true,
|
||||
"bigPackageSizeSupport": false,
|
||||
"useIsolateContext": true
|
||||
}
|
||||
}
|
||||