Initial Commit

yzb
yzb 6 months ago
commit 07d22dc2ed

14
.gitignore vendored

@ -0,0 +1,14 @@
# Windows
[Dd]esktop.ini
Thumbs.db
$RECYCLE.BIN/
# macOS
.DS_Store
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
# Node.js
node_modules/

@ -0,0 +1,12 @@
# 云开发 quickstart
这是云开发的快速启动指引,其中演示了如何上手使用云开发的三大基础能力:
- 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 文档型数据库
- 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理
- 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码
## 参考文档
- [云开发文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html)

@ -0,0 +1,7 @@
{
"permissions": {
"openapi": [
"wxacode.get"
]
}
}

@ -0,0 +1,238 @@
const cloud = require("wx-server-sdk");
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
});
const db = cloud.database();
// 获取openid
const getOpenId = async () => {
// 获取基础信息
const wxContext = cloud.getWXContext();
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
};
};
// 获取小程序二维码
const getMiniProgramCode = async () => {
// 获取小程序二维码的buffer
const resp = await cloud.openapi.wxacode.get({
path: "pages/index/index",
});
const { buffer } = resp;
// 将图片上传云存储空间
const upload = await cloud.uploadFile({
cloudPath: "code.png",
fileContent: buffer,
});
return upload.fileID;
};
// 创建集合
const createCollection = async () => {
try {
// 创建集合
await db.createCollection("sales");
await db.collection("sales").add({
// data 字段表示需新增的 JSON 数据
data: {
region: "华东",
city: "上海",
sales: 11,
},
});
await db.collection("sales").add({
// data 字段表示需新增的 JSON 数据
data: {
region: "华东",
city: "南京",
sales: 11,
},
});
await db.collection("sales").add({
// data 字段表示需新增的 JSON 数据
data: {
region: "华南",
city: "广州",
sales: 22,
},
});
await db.collection("sales").add({
// data 字段表示需新增的 JSON 数据
data: {
region: "华南",
city: "深圳",
sales: 22,
},
});
return {
success: true,
};
} catch (e) {
// 这里catch到的是该collection已经存在从业务逻辑上来说是运行成功的所以catch返回success给前端避免工具在前端抛出异常
return {
success: true,
data: "create collection success",
};
}
};
// 查询数据
const selectRecord = async () => {
// 返回数据库查询结果
return await db.collection("sales").get();
};
// 更新数据
const updateRecord = async (event) => {
try {
// 遍历修改数据库信息
for (let i = 0; i < event.data.length; i++) {
await db
.collection("sales")
.where({
_id: event.data[i]._id,
})
.update({
data: {
sales: event.data[i].sales,
},
});
}
return {
success: true,
data: event.data,
};
} catch (e) {
return {
success: false,
errMsg: e,
};
}
};
// 新增数据
const insertRecord = async (event) => {
try {
const insertRecord = event.data;
// 插入数据
await db.collection("sales").add({
data: {
region: insertRecord.region,
city: insertRecord.city,
sales: Number(insertRecord.sales),
},
});
return {
success: true,
data: event.data,
};
} catch (e) {
return {
success: false,
errMsg: e,
};
}
};
// 删除数据
const deleteRecord = async (event) => {
try {
await db
.collection("sales")
.where({
_id: event.data._id,
})
.remove();
return {
success: true,
};
} catch (e) {
return {
success: false,
errMsg: e,
};
}
};
// const getOpenId = require('./getOpenId/index');
// const getMiniProgramCode = require('./getMiniProgramCode/index');
// const createCollection = require('./createCollection/index');
// const selectRecord = require('./selectRecord/index');
// const updateRecord = require('./updateRecord/index');
// const sumRecord = require('./sumRecord/index');
// const fetchGoodsList = require('./fetchGoodsList/index');
// const genMpQrcode = require('./genMpQrcode/index');
// 查询T_user表数据
const queryTUser = async () => {
try {
const result = await db.collection("T_user").get();
return {
success: true,
data: result.data,
count: result.data.length
};
} catch (e) {
return {
success: false,
error: e.message
};
}
};
// 添加测试用户到T_user表
const addTestUser = async (event) => {
try {
const userData = event.userData || {
sno: "230340151",
sname: "测试用户",
phone: "13800138000",
password: "100997@mkg",
major: "计算机科学",
sushe: "1号楼 101",
年级: "大三",
avatar: "https://via.placeholder.com/100x100/4285F4/ffffff?text=T"
};
const result = await db.collection("T_user").add({
data: userData
});
return {
success: true,
data: result,
message: "测试用户添加成功"
};
} catch (e) {
return {
success: false,
error: e.message
};
}
};
// 云函数入口函数
exports.main = async (event, context) => {
switch (event.type) {
case "getOpenId":
return await getOpenId();
case "getMiniProgramCode":
return await getMiniProgramCode();
case "createCollection":
return await createCollection();
case "selectRecord":
return await selectRecord();
case "updateRecord":
return await updateRecord(event);
case "insertRecord":
return await insertRecord(event);
case "deleteRecord":
return await deleteRecord(event);
case "queryTUser":
return await queryTUser();
case "addTestUser":
return await addTestUser(event);
}
};

@ -0,0 +1,14 @@
{
"name": "quickstartFunctions",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~2.4.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

@ -0,0 +1,21 @@
// app.js
App({
onLaunch: function () {
this.globalData = {
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用wx.cloud.xxx会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
env: "cloud1-7gmt1869f0703287"
};
if (!wx.cloud) {
console.error("请使用 2.2.3 或以上的基础库以使用云能力");
} else {
wx.cloud.init({
env: this.globalData.env,
traceUser: true,
});
}
},
});

@ -0,0 +1,41 @@
{
"pages": [
"pages/index/index",
"pages/logs/logs",
"pages/register/register",
"pages/interests/interests",
"pages/main/main",
"pages/pricing/pricing",
"pages/publish/publish",
"pages/buy/buy",
"pages/purchase/purchase",
"pages/profile/profile"
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "校园二手交易",
"navigationBarBackgroundColor": "#f5f5f5",
"backgroundColor": "#f5f5f5"
},
"requiredPrivateInfos": [
"chooseAddress",
"chooseLocation",
"choosePoi",
"getLocation",
"onLocationChange",
"startLocationUpdate",
"startLocationUpdateBackground"
],
"requiredBackgroundModes": [
"location"
],
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
},
"style": "v2",
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}

@ -0,0 +1,52 @@
/**app.wxss**/
/* 全局样式重置 */
page {
height: 100%;
background-color: #f5f5f5;
}
/* 容器样式 */
/**app.wxss**/
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
/* 通用文本样式 */
text {
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimSun, sans-serif;
}
/* 通用按钮样式 */
button {
border-radius: 8rpx;
font-size: 32rpx;
}
button::after {
border: none;
}
/* 通用输入框样式 */
input {
font-size: 32rpx;
color: #333;
}
/* 通用图片样式 */
image {
display: block;
}
/* 通用滚动条样式 */
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}

@ -0,0 +1,28 @@
Component({
/**
* 页面的初始数据
*/
data: {
showTip: false,
},
properties: {
showTipProps: Boolean,
title:String,
content:String
},
observers: {
showTipProps: function(showTipProps) {
this.setData({
showTip: showTipProps
});
}
},
methods: {
onClose(){
this.setData({
showTip: !this.data.showTip
});
},
}
});

@ -0,0 +1,4 @@
{
"usingComponents": {},
"component": true
}

@ -0,0 +1,10 @@
<!--miniprogram/components/cloudTipModal/index.wxml-->
<!-- wx:if="{{showUploadTip}}" -->
<view class="install_tip" wx:if="{{showTip}}">
<view class="install_tip_back"></view>
<view class="install_tip_detail">
<image class="install_tip_close" bind:tap="onClose" src="../../images/icons/close.png"/>
<view class="install_tip_detail_title">{{title}}</view>
<view class="install_tip_detail_tip">{{content}}</view>
</view>
</view>

@ -0,0 +1,60 @@
.install_tip_back {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,0.4);
z-index: 1;
}
.install_tip_close{
position:absolute;
right: 10rpx;
top: 10rpx;
width: 32px;
height: 32px;
/* background-color: red; */
}
.install_tip_detail {
position: fixed;
background-color: white;
right: 0;
bottom: 0;
left: 0;
border-radius: 40rpx 40rpx 0 0;
padding: 50rpx 50rpx 100rpx 50rpx;
z-index: 9;
}
.install_tip_detail_title {
font-weight: 400;
font-size: 40rpx;
text-align: center;
}
.install_tip_detail_tip {
font-size: 25rpx;
color: rgba(0,0,0,0.4);
margin-top: 20rpx;
text-align: left;
}
.install_tip_detail_buttons {
padding-top: 50rpx;
display: flex;
}
.install_tip_detail_button {
color: #07C160;
font-weight: 500;
background-color: rgba(0,0,0,0.1);
width: 40%;
text-align: center;
/* height: 90rpx; */
/* line-height: 90rpx; */
border-radius: 10rpx;
margin: 0 auto;
}
.install_tip_detail_button_primary {
background-color: #07C160;
color: #fff;
}

@ -0,0 +1,6 @@
const envList = [];
const isMac = false;
module.exports = {
envList,
isMac
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,418 @@
// pages/buy/buy.js
Page({
/**
* 页面的初始数据
*/
data: {
// 搜索相关
searchKeyword: '',
// 筛选条件
categories: ['全部分类', '电子产品', '图书文具', '服装鞋帽', '运动户外', '美妆个护', '家居生活', '其他'],
selectedCategory: 0,
categoryNavItems: [
{ id: 0, name: '全部' },
{ id: 1, name: '电子产品' },
{ id: 2, name: '图书文具' },
{ id: 3, name: '服装鞋帽' },
{ id: 4, name: '运动户外' },
{ id: 5, name: '美妆个护' },
{ id: 6, name: '家居生活' },
{ id: 7, name: '其他' }
],
selectedCategoryIndex: 0,
priceRanges: ['价格范围', '0-50元', '50-100元', '100-200元', '200-500元', '500元以上'],
selectedPriceRange: 0,
sortOptions: ['最新发布', '价格从低到高', '价格从高到低', '评分最高'],
selectedSort: 0,
// 商品列表
products: [],
filteredProducts: [],
// 分页相关
currentPage: 1,
pageSize: 10,
hasMore: true,
// 页面状态
refreshing: false,
loading: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.loadProducts();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
// 页面显示时刷新数据
if (this.data.products.length === 0) {
this.loadProducts();
}
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.onRefresh();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
this.loadMore();
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '校园二手交易 - 发现好物',
path: '/pages/buy/buy'
}
},
/**
* 搜索输入事件
*/
onSearchInput(e) {
this.setData({
searchKeyword: e.detail.value
});
// 实时搜索,不需要点击搜索按钮
this.filterProducts();
},
/**
* 搜索按钮点击事件
*/
onSearch() {
this.filterProducts();
},
/**
* 清空搜索
*/
onClearSearch() {
this.setData({
searchKeyword: ''
});
this.filterProducts();
},
/**
* 分类导航点击事件
*/
onCategoryNavTap(e) {
const index = parseInt(e.currentTarget.dataset.index);
this.setData({
selectedCategoryIndex: index,
selectedCategory: index
});
this.filterProducts();
},
/**
* 分类选择事件
*/
onCategoryChange(e) {
const index = e.detail.value;
this.setData({
selectedCategory: index,
selectedCategoryIndex: index
});
this.filterProducts();
},
/**
* 价格范围选择事件
*/
onPriceRangeChange(e) {
this.setData({
selectedPriceRange: e.detail.value
});
this.filterProducts();
},
/**
* 排序方式选择事件
*/
onSortChange() {
wx.showActionSheet({
itemList: this.data.sortOptions,
success: (res) => {
this.setData({
selectedSort: res.tapIndex
});
this.sortProducts();
}
});
},
/**
* 商品点击事件
*/
onProductTap(e) {
const product = e.currentTarget.dataset.product;
wx.navigateTo({
url: `/pages/product-detail/product-detail?id=${product.id}`
});
},
/**
* 下拉刷新
*/
onRefresh() {
this.setData({
refreshing: true,
currentPage: 1,
hasMore: true
});
// 模拟网络请求
setTimeout(() => {
this.loadProducts(true);
this.setData({
refreshing: false
});
wx.stopPullDownRefresh();
}, 1000);
},
/**
* 加载更多
*/
loadMore() {
if (this.data.loading || !this.data.hasMore) {
return;
}
this.setData({
loading: true
});
// 模拟网络请求
setTimeout(() => {
const newProducts = this.generateMockProducts(this.data.currentPage + 1, this.data.pageSize);
if (newProducts.length > 0) {
this.setData({
products: [...this.data.products, ...newProducts],
currentPage: this.data.currentPage + 1,
hasMore: newProducts.length === this.data.pageSize
});
this.filterProducts();
}
this.setData({
loading: false
});
}, 500);
},
/**
* 加载商品数据
*/
loadProducts(refresh = false) {
this.setData({
loading: true
});
// 模拟网络请求
setTimeout(() => {
const products = this.generateMockProducts(1, this.data.pageSize);
this.setData({
products: products,
filteredProducts: products,
currentPage: 1,
hasMore: products.length === this.data.pageSize,
loading: false
});
}, 800);
},
/**
* 筛选商品
*/
filterProducts() {
let filtered = this.data.products;
// 关键词搜索
if (this.data.searchKeyword) {
const keyword = this.data.searchKeyword.toLowerCase();
filtered = filtered.filter(product =>
product.name.toLowerCase().includes(keyword) ||
product.description.toLowerCase().includes(keyword) ||
product.category.includes(keyword)
);
}
// 分类筛选
if (this.data.selectedCategory > 0) {
const category = this.data.categories[this.data.selectedCategory];
filtered = filtered.filter(product => product.category === category);
}
// 价格范围筛选
if (this.data.selectedPriceRange > 0) {
const priceRange = this.data.priceRanges[this.data.selectedPriceRange];
filtered = filtered.filter(product => {
const price = parseFloat(product.price);
switch (priceRange) {
case '0-50元': return price <= 50;
case '50-100元': return price > 50 && price <= 100;
case '100-200元': return price > 100 && price <= 200;
case '200-500元': return price > 200 && price <= 500;
case '500元以上': return price > 500;
default: return true;
}
});
}
this.setData({
filteredProducts: filtered
});
this.sortProducts();
},
/**
* 排序商品
*/
sortProducts() {
let sorted = [...this.data.filteredProducts];
switch (this.data.selectedSort) {
case 0: // 最新发布
sorted.sort((a, b) => new Date(b.publishTime) - new Date(a.publishTime));
break;
case 1: // 价格从低到高
sorted.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
break;
case 2: // 价格从高到低
sorted.sort((a, b) => parseFloat(b.price) - parseFloat(a.price));
break;
case 3: // 评分最高
sorted.sort((a, b) => parseFloat(b.sellerRating) - parseFloat(a.sellerRating));
break;
}
this.setData({
filteredProducts: sorted
});
},
/**
* 生成模拟商品数据
*/
generateMockProducts(page, pageSize) {
if (page > 3) return []; // 模拟只有3页数据
const mockProducts = [
{
id: 1,
name: 'iPhone 13 Pro Max',
description: '99新256GB国行在保无划痕无磕碰',
price: '5999',
originalPrice: '8999',
discount: '6.7',
category: '电子产品',
condition: '99新',
location: '闵行校区',
publishTime: '2小时前',
image: '/images/iphone13.jpg',
sellerAvatar: '/images/avatar1.jpg',
sellerName: '张同学',
sellerRating: '4.8',
status: 'selling'
},
{
id: 2,
name: '高等数学教材',
description: '同济大学第七版,几乎全新,有少量笔记',
price: '25',
category: '图书文具',
condition: '95新',
location: '徐汇校区',
publishTime: '1天前',
image: '/images/math-book.jpg',
sellerAvatar: '/images/avatar2.jpg',
sellerName: '李同学',
sellerRating: '4.9',
status: 'selling'
},
{
id: 3,
name: 'Nike Air Force 1',
description: '白色经典款42码穿过几次保养很好',
price: '299',
originalPrice: '799',
discount: '3.7',
category: '运动户外',
condition: '85新',
location: '松江校区',
publishTime: '3天前',
image: '/images/nike-shoes.jpg',
sellerAvatar: '/images/avatar3.jpg',
sellerName: '王同学',
sellerRating: '4.7',
status: 'selling'
},
{
id: 4,
name: 'MacBook Pro 2021',
description: 'M1芯片16GB内存512GB硬盘性能强劲',
price: '8999',
originalPrice: '12999',
discount: '6.9',
category: '电子产品',
condition: '98新',
location: '闵行校区',
publishTime: '5小时前',
image: '/images/macbook.jpg',
sellerAvatar: '/images/avatar4.jpg',
sellerName: '赵同学',
sellerRating: '4.9',
status: 'selling'
},
{
id: 5,
name: 'SK-II神仙水',
description: '230ml正品保证还剩大半瓶个人原因转让',
price: '499',
originalPrice: '1540',
discount: '3.2',
category: '美妆个护',
condition: '90新',
location: '徐汇校区',
publishTime: '1天前',
image: '/images/sk2.jpg',
sellerAvatar: '/images/avatar5.jpg',
sellerName: '陈同学',
sellerRating: '4.8',
status: 'selling'
}
];
// 根据页码返回数据
const startIndex = (page - 1) * pageSize;
return mockProducts.slice(startIndex, startIndex + pageSize);
}
})

@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "商品购买",
"navigationBarBackgroundColor": "#4285F4",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}

@ -0,0 +1,166 @@
<!-- 商品购买页面 -->
<view class="container">
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-input">
<icon type="search" size="30" class="search-icon"></icon>
<input
type="text"
placeholder="搜索商品名称、类别..."
bindinput="onSearchInput"
value="{{searchKeyword}}"
class="search-field"
/>
<view class="search-cancel" bindtap="onClearSearch" wx:if="{{searchKeyword}}">
<text>取消</text>
</view>
<button class="search-btn" bindtap="onSearch">搜索</button>
</view>
</view>
<!-- 分类导航 -->
<view class="category-nav">
<view
class="category-item {{selectedCategoryIndex === index ? 'active' : ''}}"
wx:for="{{categoryNavItems}}"
wx:key="id"
bindtap="onCategoryNavTap"
data-index="{{index}}"
>
<text class="category-text">{{item.name}}</text>
</view>
</view>
<!-- 筛选条件 -->
<view class="filter-bar">
<picker
range="{{categories}}"
value="{{selectedCategory}}"
bindchange="onCategoryChange"
class="filter-item"
>
<view class="filter-display">
<text>{{categories[selectedCategory] || '全部分类'}}</text>
<icon type="arrow-down" size="12"></icon>
</view>
</picker>
<picker
range="{{priceRanges}}"
value="{{selectedPriceRange}}"
bindchange="onPriceRangeChange"
class="filter-item"
>
<view class="filter-display">
<text>{{priceRanges[selectedPriceRange] || '价格范围'}}</text>
<icon type="arrow-down" size="12"></icon>
</view>
</picker>
<view class="filter-item" bindtap="onSortChange">
<view class="filter-display">
<text>{{sortOptions[selectedSort]}}</text>
<icon type="arrow-down" size="12"></icon>
</view>
</view>
</view>
<!-- 商品列表 -->
<scroll-view
class="product-list"
scroll-y
bindscrolltolower="onReachBottom"
refresher-enabled="true"
bindrefresherrefresh="onRefresh"
refresher-triggered="{{refreshing}}"
>
<!-- 商品网格容器 -->
<view class="product-grid">
<!-- 商品卡片 -->
<view
class="product-card"
wx:for="{{filteredProducts}}"
wx:key="id"
bindtap="onProductTap"
data-product="{{item}}"
>
<!-- 商品图片 -->
<view class="product-image-container">
<image
src="{{item.image}}"
mode="aspectFill"
class="product-image"
/>
<view class="product-status" wx:if="{{item.status === 'sold'}}">
<text>已售出</text>
</view>
</view>
<!-- 商品信息 -->
<view class="product-info">
<!-- 卖家信息 -->
<view class="seller-info">
<image
src="{{item.sellerAvatar}}"
mode="aspectFill"
class="seller-avatar"
/>
<text class="seller-name">{{item.sellerName}}</text>
<view class="seller-rating" wx:if="{{item.sellerRating}}">
<text class="rating-text">{{item.sellerRating}}</text>
<icon type="star" size="12" class="star-icon"></icon>
</view>
</view>
<!-- 商品标题 -->
<view class="product-title">
<text class="title-text">{{item.name}}</text>
</view>
<!-- 商品描述 -->
<view class="product-description">
<text class="description-text">{{item.description}}</text>
</view>
<!-- 价格信息 -->
<view class="price-info">
<text class="current-price">¥{{item.price}}</text>
<text class="original-price" wx:if="{{item.originalPrice}}">¥{{item.originalPrice}}</text>
<view class="discount-badge" wx:if="{{item.discount}}">
<text>{{item.discount}}折</text>
</view>
</view>
<!-- 商品标签 -->
<view class="product-tags">
<text class="tag category-tag">{{item.category}}</text>
<text class="tag condition-tag">{{item.condition}}</text>
<text class="tag location-tag">{{item.location}}</text>
</view>
<!-- 发布时间 -->
<view class="publish-time">
<text class="time-text">{{item.publishTime}}</text>
</view>
</view>
</view>
</view>
<!-- 加载更多 -->
<view class="load-more" wx:if="{{hasMore}}">
<text>加载中...</text>
</view>
<!-- 没有更多数据 -->
<view class="no-more" wx:if="{{!hasMore && filteredProducts.length > 0}}">
<text>没有更多商品了</text>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{filteredProducts.length === 0}}">
<image src="/images/empty-product.png" class="empty-image" />
<text class="empty-text">暂无商品</text>
<text class="empty-subtext">换个筛选条件试试</text>
</view>
</scroll-view>
</view>

@ -0,0 +1,349 @@
/* 商品购买页面样式 */
.container {
height: 100vh;
background-color: #f5f5f5;
padding-top: 0;
}
/* 搜索栏样式 */
.search-bar {
padding: 0;
background-color: #fff;
border-bottom: 1rpx solid #e0e0e0;
}
.search-input {
display: flex;
align-items: center;
background-color: #f8f9fa;
border-radius: 0;
padding: 20rpx;
height: 100rpx;
}
.search-icon {
margin-right: 20rpx;
color: #999;
}
.search-field {
flex: 1;
font-size: 32rpx;
color: #333;
height: 60rpx;
line-height: 60rpx;
}
.search-cancel {
padding: 10rpx 20rpx;
background-color: #e9ecef;
border-radius: 30rpx;
font-size: 28rpx;
color: #666;
margin-right: 20rpx;
height: 60rpx;
line-height: 40rpx;
}
.search-btn {
background-color: #007bff;
color: #fff;
border: none;
border-radius: 30rpx;
padding: 10rpx 30rpx;
font-size: 28rpx;
line-height: 1;
margin-left: 20rpx;
height: 60rpx;
min-width: 120rpx;
}
/* 分类导航 */
.category-nav {
display: flex;
white-space: nowrap;
padding: 24rpx 30rpx;
background-color: #fff;
border-bottom: 1rpx solid #f0f0f0;
overflow-x: auto;
}
.category-item {
padding: 12rpx 32rpx;
margin-right: 20rpx;
border-radius: 40rpx;
background-color: #f8f9fa;
border: 1rpx solid #e9ecef;
font-size: 28rpx;
color: #6c757d;
transition: all 0.3s ease;
flex-shrink: 0;
}
.category-item.active {
background-color: #007bff;
border-color: #007bff;
color: #fff;
}
.category-text {
font-size: 28rpx;
font-weight: 500;
}
/* 筛选栏样式 */
.filter-bar {
display: flex;
background-color: #fff;
border-bottom: 1rpx solid #e0e0e0;
padding: 20rpx;
}
.filter-item {
flex: 1;
text-align: center;
font-size: 26rpx;
color: #666;
}
.filter-display {
display: flex;
align-items: center;
justify-content: center;
}
/* 商品列表样式 */
.product-list {
height: calc(100vh - 180rpx);
}
/* 商品网格容器 */
.product-grid {
display: flex;
flex-wrap: wrap;
padding: 10rpx;
gap: 10rpx;
box-sizing: border-box;
}
/* 商品卡片样式 */
.product-card {
width: calc(50% - 8rpx);
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
overflow: hidden;
margin-bottom: 10rpx;
box-sizing: border-box;
flex-shrink: 0;
}
.product-image-container {
position: relative;
height: 200rpx;
}
.product-image {
width: 100%;
height: 100%;
}
.product-status {
position: absolute;
top: 10rpx;
right: 10rpx;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 4rpx 8rpx;
border-radius: 10rpx;
font-size: 18rpx;
}
/* 商品信息样式 */
.product-info {
padding: 15rpx;
}
/* 卖家信息样式 */
.seller-info {
display: flex;
align-items: center;
margin-bottom: 10rpx;
}
.seller-avatar {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
margin-right: 8rpx;
}
.seller-name {
font-size: 22rpx;
color: #666;
margin-right: 8rpx;
}
.seller-rating {
display: flex;
align-items: center;
background-color: #fff8e1;
padding: 2rpx 6rpx;
border-radius: 8rpx;
}
.rating-text {
font-size: 18rpx;
color: #ff9800;
margin-right: 3rpx;
}
.star-icon {
color: #ff9800;
font-size: 16rpx;
}
/* 商品标题样式 */
.product-title {
margin-bottom: 8rpx;
}
.title-text {
font-size: 26rpx;
font-weight: bold;
color: #333;
line-height: 1.3;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
/* 商品描述样式 */
.product-description {
margin-bottom: 10rpx;
}
.description-text {
font-size: 22rpx;
color: #666;
line-height: 1.4;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
/* 价格信息样式 */
.price-info {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
.current-price {
font-size: 28rpx;
font-weight: bold;
color: #ff4444;
margin-right: 8rpx;
}
.original-price {
font-size: 20rpx;
color: #999;
text-decoration: line-through;
margin-right: 8rpx;
}
.discount-badge {
background-color: #ff4444;
color: #fff;
padding: 2rpx 6rpx;
border-radius: 6rpx;
font-size: 18rpx;
}
/* 商品标签样式 */
.product-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 8rpx;
}
.tag {
font-size: 18rpx;
padding: 2rpx 6rpx;
border-radius: 6rpx;
margin-right: 6rpx;
margin-bottom: 4rpx;
}
.category-tag {
background-color: #e3f2fd;
color: #1976d2;
}
.condition-tag {
background-color: #f3e5f5;
color: #7b1fa2;
}
.location-tag {
background-color: #e8f5e8;
color: #388e3c;
}
/* 发布时间样式 */
.publish-time {
font-size: 18rpx;
color: #999;
}
/* 加载更多样式 */
.load-more, .no-more {
text-align: center;
padding: 40rpx;
font-size: 26rpx;
color: #999;
}
/* 空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 40rpx;
}
.empty-image {
width: 200rpx;
height: 200rpx;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 32rpx;
color: #666;
margin-bottom: 15rpx;
}
.empty-subtext {
font-size: 26rpx;
color: #999;
}
/* 响应式调整 */
@media (max-width: 750rpx) {
.product-card {
margin: 15rpx;
}
.product-info {
padding: 20rpx;
}
.product-image-container {
height: 250rpx;
}
}

@ -0,0 +1,223 @@
// index.js
Page({
data: {
studentId: '',
password: '',
isLoginDisabled: false
},
onLoad() {
// 检查本地存储中是否有登录信息
this.checkLoginStatus();
},
// 检查登录状态
checkLoginStatus() {
const token = wx.getStorageSync('token');
const userInfo = wx.getStorageSync('userInfo');
if (token && userInfo) {
// 如果已登录,跳转到主页面
wx.redirectTo({
url: '/pages/main/main'
});
}
},
// 学号/手机号输入处理
onInputStudentId(e) {
const studentId = e.detail.value.trim();
this.setData({
studentId: studentId
});
this.checkLoginButton();
},
// 密码输入处理
onInputPassword(e) {
const password = e.detail.value.trim();
this.setData({
password: password
});
this.checkLoginButton();
},
// 检查登录按钮状态
checkLoginButton() {
// 按钮始终保持可用状态
this.setData({
isLoginDisabled: false
});
},
// 登录处理
onLogin() {
const { studentId, password } = this.data;
// 简单的前端验证
if (!this.validateInput(studentId, password)) {
return;
}
// 显示加载中
wx.showLoading({
title: '登录中...',
mask: true
});
// 调用云数据库进行真实登录验证
this.realLogin(studentId, password);
},
// 输入验证
validateInput(studentId, password) {
if (!studentId) {
wx.showToast({
title: '请输入学号或手机号',
icon: 'none'
});
return false;
}
if (!password) {
wx.showToast({
title: '请输入密码',
icon: 'none'
});
return false;
}
if (password.length < 6) {
wx.showToast({
title: '密码长度不能少于6位',
icon: 'none'
});
return false;
}
return true;
},
// 真实登录验证(查询云数据库)
realLogin(loginId, password) {
const db = wx.cloud.database();
// 查询数据库中的T_user表
db.collection('T_user').where({
$or: [
{ phone: loginId }, // 手机号匹配
{ sno: loginId } // 学号匹配
],
password: password // 密码匹配
}).get({
success: (res) => {
wx.hideLoading();
if (res.data.length > 0) {
// 登录成功
const userData = res.data[0];
const userInfo = {
_id: userData._id,
sno: userData.sno,
sname: userData.sname,
phone: userData.phone,
major: userData.major,
sushe: userData.sushe,
grade: userData.年级,
avatar: userData.avatar || 'https://via.placeholder.com/100x100/4CAF50/ffffff?text=U'
};
// 保存登录信息到本地存储
wx.setStorageSync('token', 'user_token_' + userData._id);
wx.setStorageSync('userInfo', userInfo);
wx.showToast({
title: '登录成功',
icon: 'success',
duration: 1500
});
// 跳转到主页面
setTimeout(() => {
wx.redirectTo({
url: '/pages/main/main'
});
}, 1500);
} else {
// 登录失败
wx.showToast({
title: '账号或密码错误',
icon: 'none'
});
}
},
fail: (err) => {
wx.hideLoading();
console.error('登录查询失败:', err);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
});
},
// 注册处理
onRegister() {
wx.navigateTo({
url: '/pages/register/register'
});
},
// 忘记密码处理
onForgotPassword() {
wx.navigateTo({
url: '/pages/forgot-password/forgot-password'
});
},
// 微信一键登录
onGetPhoneNumber(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
// 用户同意授权
const { encryptedData, iv } = e.detail;
wx.showLoading({
title: '登录中...',
mask: true
});
// 模拟微信登录
setTimeout(() => {
const userInfo = {
studentId: 'wx_' + Date.now().toString().slice(-6),
nickname: '微信用户',
avatar: 'https://via.placeholder.com/100x100/07C160/ffffff?text=W',
campus: '微信用户',
department: '微信用户'
};
wx.setStorageSync('token', 'wx_token_' + Date.now());
wx.setStorageSync('userInfo', userInfo);
wx.hideLoading();
wx.showToast({
title: '微信登录成功',
icon: 'success'
});
setTimeout(() => {
wx.redirectTo({
url: '/pages/main/main'
});
}, 1500);
}, 1500);
} else {
// 用户拒绝授权
wx.showToast({
title: '授权失败',
icon: 'none'
});
}
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {
}
}

@ -0,0 +1,71 @@
<!--index.wxml-->
<view class="page-container">
<view class="login-container">
<!-- 顶部logo和标题 -->
<view class="header">
<image class="logo" src="https://ts1.tc.mm.bing.net/th/id/R-C.0c942a1a8df6bb32de224a7c78c3af92?rik=SEx%2b%2fzYxnPfqwg&riu=http%3a%2f%2fyuanxiao.mpacc.cc%2fuploadfile%2f2022%2f1109%2f20221109052556257.png&ehk=%2bVL02gwPQzun0%2fzDFjxp5xUoH005t%2bS57Qff156jez8%3d&risl=&pid=ImgRaw&r=0" mode="aspectFit"></image>
<text class="title">校园二手交易</text>
<text class="subtitle">安全便捷的校园交易平台</text>
</view>
<!-- 登录表单 -->
<view class="login-form">
<view class="form-group">
<text class="label">学号/手机号</text>
<input
class="input"
type="number"
placeholder="请输入学号或手机号"
bindinput="onInputStudentId"
value="{{studentId}}"
/>
</view>
<view class="form-group">
<text class="label">密码</text>
<input
class="input"
type="password"
placeholder="请输入密码"
bindinput="onInputPassword"
value="{{password}}"
password
/>
</view>
<!-- 登录按钮 -->
<button
class="login-btn {{isLoginDisabled ? 'disabled' : ''}}"
bindtap="onLogin"
disabled="{{isLoginDisabled}}"
>
登录
</button>
<!-- 注册链接 -->
<view class="register-link">
<text>还没有账号?</text>
<text class="link" bindtap="onRegister">立即注册</text>
</view>
<!-- 忘记密码 -->
<view class="forgot-password">
<text class="link" bindtap="onForgotPassword">忘记密码?</text>
</view>
</view>
<!-- 快速登录选项 -->
<view class="quick-login">
<view class="divider">
<text class="divider-text">或使用以下方式登录</text>
</view>
<view class="quick-login-buttons">
<button class="quick-btn wechat" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
<image class="quick-icon" src="https://via.placeholder.com/40x40/07C160/ffffff?text=W" mode="aspectFit"></image>
<text>微信一键登录</text>
</button>
</view>
</view>
</view>
</view>

@ -0,0 +1,233 @@
/**index.wxss**/
page {
height: 100vh;
position: relative;
}
.page-container {
height: 100vh;
position: relative;
}
.background-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.login-container {
flex: 1;
display: flex;
flex-direction: column;
padding: 60rpx 40rpx 40rpx;
box-sizing: border-box;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 80rpx;
}
.logo {
width: 200rpx;
height: 200rpx;
border-radius: 80rpx;
background: rgba(255, 255, 255, 0.2);
margin-bottom: 30rpx;
display: block;
margin-left: auto;
margin-right: auto;
}
.title {
display: block;
font-size: 50rpx;
font-weight: bold;
color: rgb(0, 0, 0);
margin-bottom: 16rpx;
}
.subtitle {
display: block;
font-size: 40rpx;
color: rgba(0, 0, 0, 0.8);
}
/* 登录表单样式 */
.login-form {
background: rgba(255, 254, 254, 0.95);
border-radius: 24rpx;
padding: 60rpx 40rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.15);
margin-bottom: 40rpx;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
}
.form-group {
margin-bottom: 40rpx;
}
.label {
display: block;
font-size: 28rpx;
color: #333333;
margin-bottom: 20rpx;
font-weight: 500;
}
.input {
width: 100%;
height: 80rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
background: #fafafa;
transition: all 0.3s ease;
}
.input:focus {
border-color: #ffffff;
background: #ffffff;
box-shadow: 0 0 0 4rpx rgba(76, 175, 80, 0.1);
}
/* 登录按钮样式 */
.login-btn {
width: 100%;
height: 88rpx;
background: linear-gradient(135deg, rgb(118, 116, 247) 0%, rgb(148, 125, 250) 100%);
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 600;
margin-top: 20rpx;
transition: all 0.3s ease;
}
.login-btn:active {
transform: scale(0.98);
opacity: 0.9;
}
.login-btn.disabled {
background: #cccccc;
color: #999999;
transform: none;
opacity: 0.6;
}
/* 注册链接样式 */
.register-link {
text-align: center;
margin: 40rpx 0 20rpx;
font-size: 26rpx;
color: #666666;
}
.link {
color: #a4acefff;
font-weight: 500;
margin-left: 10rpx;
}
.link:active {
opacity: 0.7;
}
/* 忘记密码样式 */
.forgot-password {
text-align: center;
margin-bottom: 20rpx;
}
/* 快速登录样式 */
.quick-login {
background: rgba(255, 255, 255, 0.1);
border-radius: 24rpx;
padding: 40rpx;
backdrop-filter: blur(10rpx);
}
.divider {
position: relative;
text-align: center;
margin-bottom: 40rpx;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1rpx;
background: rgba(255, 255, 255, 0.3);
}
.divider-text {
display: inline-block;
background: rgba(255, 255, 255, 0.1);
padding: 0 20rpx;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
position: relative;
}
.quick-login-buttons {
display: flex;
justify-content: center;
}
.quick-btn {
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 44rpx;
padding: 20rpx 40rpx;
font-size: 28rpx;
color: #333333;
transition: all 0.3s ease;
}
.quick-btn:active {
transform: scale(0.95);
background: rgba(255, 255, 255, 1);
}
.quick-icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.quick-btn.wechat {
background: rgba(255, 255, 255, 0.9);
}
.quick-btn.wechat:active {
background: rgba(255, 255, 255, 1);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.login-container {
padding: 40rpx 30rpx 30rpx;
}
.login-form {
padding: 40rpx 30rpx;
}
.header {
margin-bottom: 60rpx;
}
}

@ -0,0 +1,231 @@
// pages/interests/interests.js
Page({
/**
* 页面的初始数据
*/
data: {
// 商品类别数据
categories: [
{
id: 'cosmetics',
name: '化妆品',
description: '美妆护肤产品',
icon: 'https://via.placeholder.com/60x60/FF6B9D/ffffff?text=💄'
},
{
id: 'books',
name: '二手书',
description: '教材、小说、专业书籍',
icon: 'https://via.placeholder.com/60x60/4CAF50/ffffff?text=📚'
},
{
id: 'electronics',
name: '电子产品',
description: '手机、电脑、配件',
icon: 'https://via.placeholder.com/60x60/2196F3/ffffff?text=📱'
},
{
id: 'clothing',
name: '服装鞋帽',
description: '衣服、鞋子、配饰',
icon: 'https://via.placeholder.com/60x60/FF9800/ffffff?text=👕'
},
{
id: 'sports',
name: '运动器材',
description: '健身器材、球类运动',
icon: 'https://via.placeholder.com/60x60/9C27B0/ffffff?text=⚽'
},
{
id: 'furniture',
name: '家具家电',
description: '桌椅、小家电',
icon: 'https://via.placeholder.com/60x60/795548/ffffff?text=🛋️'
},
{
id: 'stationery',
name: '文具用品',
description: '笔、本、学习用品',
icon: 'https://via.placeholder.com/60x60/607D8B/ffffff?text=✏️'
},
{
id: 'others',
name: '其他商品',
description: '其他各类商品',
icon: 'https://via.placeholder.com/60x60/757575/ffffff?text=📦'
}
],
// 已选择的商品类别
selectedInterests: [],
// 类别选中状态映射
categorySelectedMap: {}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 从本地存储获取用户信息,检查是否已有选择的兴趣
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.interests) {
this.setData({
selectedInterests: userInfo.interests
});
this.updateCategoriesSelection();
}
},
/**
* 更新商品类别的选中状态
*/
updateCategoriesSelection() {
const categorySelectedMap = {};
this.data.categories.forEach(category => {
categorySelectedMap[category.id] = this.data.selectedInterests.indexOf(category.id) > -1;
});
this.setData({
categorySelectedMap: categorySelectedMap
});
},
/**
* 商品类别点击事件
*/
onCategoryTap(e) {
const categoryId = e.currentTarget.dataset.id;
let selectedInterests = [...this.data.selectedInterests];
console.log('点击了商品类别:', categoryId);
console.log('当前已选择:', selectedInterests);
// 切换选择状态
const index = selectedInterests.indexOf(categoryId);
if (index > -1) {
// 取消选择
selectedInterests.splice(index, 1);
console.log('取消选择:', categoryId);
} else {
// 检查是否已达到最大选择数量4个
if (selectedInterests.length >= 4) {
wx.showToast({
title: '最多只能选择4种商品类别',
icon: 'none'
});
return;
}
// 选择
selectedInterests.push(categoryId);
console.log('选择:', categoryId);
}
console.log('更新后选择:', selectedInterests);
// 直接计算选中状态映射
const categorySelectedMap = {};
this.data.categories.forEach(category => {
categorySelectedMap[category.id] = selectedInterests.indexOf(category.id) > -1;
});
// 一次性更新所有数据
this.setData({
selectedInterests: selectedInterests,
categorySelectedMap: categorySelectedMap
});
},
/**
* 确认选择
*/
onConfirm() {
if (this.data.selectedInterests.length === 0) {
wx.showToast({
title: '请至少选择一个商品类别',
icon: 'none'
});
return;
}
// 显示注册成功提示
wx.showToast({
title: '注册成功,请重新登录',
icon: 'success',
duration: 2000
});
// 延迟跳转到登录界面index页面
setTimeout(() => {
wx.redirectTo({
url: '/pages/index/index'
});
}, 2000);
},
/**
* 跳过选择
*/
onSkip() {
// 显示注册成功提示
wx.showToast({
title: '注册成功,请重新登录',
icon: 'success',
duration: 2000
});
// 延迟跳转到登录界面index页面
setTimeout(() => {
wx.redirectTo({
url: '/pages/index/index'
});
}, 2000);
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,62 @@
<!--pages/interests/interests.wxml-->
<view class="page-container">
<view class="interests-container">
<!-- 顶部引导信息 -->
<view class="header">
<image class="welcome-icon" src="../" mode="aspectFit"></image>
<text class="title">欢迎来到校园二手交易平台!</text>
<text class="question">请选择您感兴趣的商品类别</text>
</view>
<!-- 商品类别选择区域 -->
<view class="interests-section">
<text class="section-title">选择您感兴趣的商品类别</text>
<text class="section-subtitle">(可多选,用于个性化商品推荐)</text>
<view class="interests-grid">
<view
class="interest-card {{categorySelectedMap[category.id] ? 'selected' : ''}}"
wx:for="{{categories}}"
wx:key="id"
bindtap="onCategoryTap"
data-id="{{category.id}}"
>
<image class="interest-icon" src="{{category.icon}}" mode="aspectFit"></image>
<text class="interest-name">{{category.name}}</text>
<text class="interest-desc">{{category.description}}</text>
</view>
</view>
</view>
<!-- 选择提示 -->
<view class="selection-hint" wx:if="{{selectedInterests.length > 0}}">
<text class="hint-text">已选择 {{selectedInterests.length}}/4 个商品类别</text>
<text class="hint-tip">系统将根据您的选择为您推荐相关商品</text>
</view>
<!-- 底部操作按钮 -->
<view class="action-buttons">
<button
class="skip-btn"
bindtap="onSkip"
wx:if="{{selectedInterests.length === 0}}"
>
暂时跳过
</button>
<button
class="confirm-btn {{selectedInterests.length === 0 ? 'disabled' : ''}}"
bindtap="onConfirm"
disabled="{{selectedInterests.length === 0}}"
>
{{selectedInterests.length === 0 ? '请至少选择一个' : '完成选择 (' + selectedInterests.length + ')'}}
</button>
</view>
<!-- 进度提示 -->
<view class="progress-hint">
<text class="progress-text">完成此步骤后,即可开始使用平台</text>
</view>
</view>
</view>

@ -0,0 +1,186 @@
/* pages/interests/interests.wxss */
.page-container {
min-height: 100vh;
background: linear-gradient(135deg, #7672fdff 0%, #9bc3ffff 100%);
padding: 40rpx 30rpx;
box-sizing: border-box;
}
.interests-container {
background: white;
border-radius: 20rpx;
padding: 40rpx 30rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 50rpx;
}
.welcome-icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 20rpx;
}
.title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.subtitle {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 5rpx;
}
.question {
display: block;
font-size: 32rpx;
color: #4285F4;
font-weight: 600;
}
/* 商品类别选择区域 */
.interests-section {
margin-bottom: 40rpx;
}
.section-title {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.section-subtitle {
display: block;
font-size: 26rpx;
color: #999;
margin-bottom: 30rpx;
}
.interests-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.interest-card {
background: #f8f9fa;
border: 2rpx solid #e9ecef;
border-radius: 15rpx;
padding: 30rpx 20rpx;
text-align: center;
transition: all 0.3s ease;
cursor: pointer;
}
.interest-card.selected {
background: #4285F4;
border-color: #4285F4;
transform: translateY(-5rpx);
box-shadow: 0 10rpx 20rpx rgba(66, 133, 244, 0.3);
}
.interest-card.selected .interest-name,
.interest-card.selected .interest-desc {
color: white;
}
.interest-icon {
width: 60rpx;
height: 60rpx;
margin-bottom: 15rpx;
}
.interest-name {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 5rpx;
}
.interest-desc {
display: block;
font-size: 22rpx;
color: #666;
}
/* 选择提示 */
.selection-hint {
background: #e8f4fd;
border: 1rpx solid #b3e0ff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 30rpx;
text-align: center;
}
.hint-text {
display: block;
font-size: 28rpx;
color: #0066cc;
font-weight: 600;
margin-bottom: 5rpx;
}
.hint-tip {
display: block;
font-size: 24rpx;
color: #666;
}
/* 底部操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-bottom: 30rpx;
}
.skip-btn {
flex: 1;
background: #f8f9fa;
color: #666;
border: 2rpx solid #e9ecef;
border-radius: 50rpx;
font-size: 28rpx;
height: 80rpx;
line-height: 80rpx;
}
.confirm-btn {
flex: 1;
background: #4285F4;
color: white;
border: none;
border-radius: 50rpx;
font-size: 28rpx;
height: 80rpx;
line-height: 80rpx;
font-weight: 600;
}
.confirm-btn.disabled {
background: #ccc;
color: #999;
}
/* 进度提示 */
.progress-hint {
text-align: center;
padding: 20rpx;
}
.progress-text {
font-size: 24rpx;
color: #999;
}

@ -0,0 +1,18 @@
// logs.js
const util = require('../../utils/util.js')
Page({
data: {
logs: []
},
onLoad() {
this.setData({
logs: (wx.getStorageSync('logs') || []).map(log => {
return {
date: util.formatTime(new Date(log)),
timeStamp: log
}
})
})
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {
}
}

@ -0,0 +1,6 @@
<!--logs.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
<view class="log-item">{{index + 1}}. {{log.date}}</view>
</block>
</scroll-view>

@ -0,0 +1,16 @@
page {
height: 100vh;
display: flex;
flex-direction: column;
}
.scrollarea {
flex: 1;
overflow-y: hidden;
}
.log-item {
margin-top: 20rpx;
text-align: center;
}
.log-item:last-child {
padding-bottom: env(safe-area-inset-bottom);
}

@ -0,0 +1,303 @@
// pages/main/main.js
Page({
/**
* 页面的初始数据
*/
data: {
currentTab: 'home',
userInfo: {},
searchText: '',
// 推荐商品数据
recommendProducts: [
{
id: 1,
name: '二手iPhone 13',
price: '2999',
image: 'https://via.placeholder.com/280x200/4285F4/ffffff?text=iPhone13',
tag: '电子产品'
},
{
id: 2,
name: 'Java编程思想',
price: '35',
image: 'https://via.placeholder.com/280x200/34A853/ffffff?text=Java',
tag: '二手书'
},
{
id: 3,
name: '耐克运动鞋',
price: '180',
image: 'https://via.placeholder.com/280x200/EA4335/ffffff?text=运动鞋',
tag: '服装鞋帽'
},
{
id: 4,
name: '戴尔笔记本电脑',
price: '3200',
image: 'https://via.placeholder.com/280x200/FBBC05/ffffff?text=笔记本',
tag: '电子产品'
}
],
// 热门求购数据
hotWanted: [
{
id: 1,
title: '求购二手iPad Pro',
budget: '2500',
time: '2小时前'
},
{
id: 2,
title: '急需高数教材',
budget: '30',
time: '5小时前'
},
{
id: 3,
title: '求购健身器材',
budget: '200',
time: '1天前'
}
]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.loadUserInfo();
this.loadRecommendations();
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.loadUserInfo();
},
/**
* 加载用户信息
*/
loadUserInfo() {
const userInfo = wx.getStorageSync('userInfo') || {};
this.setData({
userInfo: userInfo
});
},
/**
* 加载推荐商品基于用户兴趣
*/
loadRecommendations() {
const userInfo = wx.getStorageSync('userInfo') || {};
const userInterests = userInfo.interests || [];
// 这里可以调用后端API获取基于用户兴趣的推荐
// 目前使用模拟数据
console.log('用户兴趣:', userInterests);
console.log('加载智能推荐商品...');
},
/**
* 搜索输入事件
*/
onSearchInput(e) {
this.setData({
searchText: e.detail.value
});
},
/**
* 功能导航点击事件
*/
onNavigateTo(e) {
const page = e.currentTarget.dataset.page;
switch(page) {
case 'pricing':
wx.navigateTo({
url: '/pages/pricing/pricing'
});
break;
case 'buy':
wx.navigateTo({
url: '/pages/buy/buy'
});
break;
case 'wanted':
wx.navigateTo({
url: '/pages/purchase/purchase'
});
break;
case 'publish':
wx.navigateTo({
url: '/pages/publish/publish'
});
break;
}
},
/**
* 商品点击事件
*/
onProductTap(e) {
const productId = e.currentTarget.dataset.id;
const product = this.data.recommendProducts.find(p => p.id === productId);
wx.showModal({
title: product.name,
content: `价格: ¥${product.price}\n类别: ${product.tag}`,
showCancel: false,
confirmText: '知道了'
});
},
/**
* 求购点击事件
*/
onWantedTap(e) {
const wantedId = e.currentTarget.dataset.id;
const wanted = this.data.hotWanted.find(w => w.id === wantedId);
wx.showModal({
title: wanted.title,
content: `预算: ¥${wanted.budget}\n发布时间: ${wanted.time}`,
showCancel: false,
confirmText: '知道了'
});
},
/**
* 底部导航切换
*/
onTabChange(e) {
const tab = e.currentTarget.dataset.tab;
if (tab === this.data.currentTab) {
return;
}
this.setData({
currentTab: tab
});
// 根据不同的tab加载不同的内容
switch(tab) {
case 'home':
this.loadHomeContent();
break;
case 'market':
this.loadMarketContent();
break;
case 'message':
this.loadMessageContent();
break;
case 'profile':
// 跳转到个人中心页面
wx.navigateTo({
url: '/pages/profile/profile'
});
break;
}
},
/**
* 加载首页内容
*/
loadHomeContent() {
console.log('加载首页内容');
},
/**
* 加载市场内容
*/
loadMarketContent() {
console.log('加载市场内容');
},
/**
* 加载消息内容
*/
loadMessageContent() {
console.log('加载消息内容');
},
/**
* 加载个人中心内容
*/
loadProfileContent() {
console.log('加载个人中心内容');
},
/**
* 用户头像点击事件
*/
onUserProfile() {
wx.showActionSheet({
itemList: ['查看资料', '设置', '退出登录'],
success: (res) => {
switch(res.tapIndex) {
case 0:
wx.showToast({
title: '查看用户资料',
icon: 'none'
});
break;
case 1:
wx.showToast({
title: '打开设置',
icon: 'none'
});
break;
case 2:
this.onLogout();
break;
}
}
});
},
/**
* 退出登录
*/
onLogout() {
wx.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除登录信息
wx.removeStorageSync('userInfo');
wx.removeStorageSync('token');
// 跳转到登录页面
wx.redirectTo({
url: '/pages/index/index'
});
}
}
});
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新');
// 立即停止下拉刷新,不显示任何提示
wx.stopPullDownRefresh();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底');
// 不执行任何操作,避免显示加载提示
}
})

@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "校园二手交易",
"navigationBarBackgroundColor": "#4285F4",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": true
}

@ -0,0 +1,101 @@
<!--pages/main/main.wxml-->
<view class="page-container">
<!-- 顶部导航栏 -->
<view class="header">
<view class="search-bar">
<image class="search-icon" src="/images/search.png" mode="aspectFit"></image>
<input class="search-input" placeholder="搜索商品、求购信息" bindinput="onSearchInput" />
</view>
<view class="user-info" bindtap="onUserProfile">
<image class="avatar" src="{{userInfo.avatar || '/images/default-avatar.png'}}" mode="aspectFit"></image>
</view>
</view>
<!-- 功能导航 -->
<view class="nav-section">
<!-- 卖家功能 -->
<view class="function-group">
<text class="group-title">我是卖家</text>
<view class="nav-grid">
<view class="nav-item" bindtap="onNavigateTo" data-page="pricing">
<image class="nav-icon" src="/images/边牧.png" mode="aspectFit"></image>
<text class="nav-text">AI定价</text>
</view>
<view class="nav-item" bindtap="onNavigateTo" data-page="publish">
<image class="nav-icon" src="/images/仓鼠.png" mode="aspectFit"></image>
<text class="nav-text">发布商品</text>
</view>
</view>
</view>
<!-- 买家功能 -->
<view class="function-group">
<text class="group-title">我是买家</text>
<view class="nav-grid">
<view class="nav-item" bindtap="onNavigateTo" data-page="buy">
<image class="nav-icon" src="/images/更多犬种.png" mode="aspectFit"></image>
<text class="nav-text">商品购买</text>
</view>
<view class="nav-item" bindtap="onNavigateTo" data-page="wanted">
<image class="nav-icon" src="/images/羊.png" mode="aspectFit"></image>
<text class="nav-text">求购</text>
</view>
</view>
</view>
</view>
<!-- 推荐商品区域 -->
<view class="recommend-section">
<view class="section-header">
<text class="section-title">为您推荐</text>
<text class="section-subtitle">基于您的兴趣智能推荐</text>
</view>
<scroll-view class="recommend-scroll" scroll-x="true">
<view class="recommend-list">
<view class="product-card" wx:for="{{recommendProducts}}" wx:key="id" bindtap="onProductTap" data-id="{{item.id}}">
<image class="product-image" src="{{item.image}}" mode="aspectFill"></image>
<view class="product-info">
<text class="product-name">{{item.name}}</text>
<text class="product-price">¥{{item.price}}</text>
<text class="product-tag">{{item.tag}}</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 热门求购 -->
<view class="wanted-section">
<view class="section-header">
<text class="section-title">热门求购</text>
<text class="section-subtitle">大家都在找什么</text>
</view>
<view class="wanted-list">
<view class="wanted-item" wx:for="{{hotWanted}}" wx:key="id" bindtap="onWantedTap" data-id="{{item.id}}">
<text class="wanted-title">{{item.title}}</text>
<text class="wanted-price">预算: ¥{{item.budget}}</text>
<text class="wanted-time">{{item.time}}</text>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="tab-bar">
<view class="tab-item {{currentTab === 'home' ? 'active' : ''}}" bindtap="onTabChange" data-tab="home">
<image class="tab-icon" src="{{currentTab === 'home' ? '/images/home-active.png' : '/images/home.png'}}"></image>
<text class="tab-text">首页</text>
</view>
<view class="tab-item {{currentTab === 'market' ? 'active' : ''}}" bindtap="onTabChange" data-tab="market">
<image class="tab-icon" src="{{currentTab === 'market' ? '/images/market-active.png' : '/images/market.png'}}"></image>
<text class="tab-text">市场</text>
</view>
<view class="tab-item {{currentTab === 'message' ? 'active' : ''}}" bindtap="onTabChange" data-tab="message">
<image class="tab-icon" src="{{currentTab === 'message' ? '/images/message-active.png' : '/images/message.png'}}"></image>
<text class="tab-text">消息</text>
</view>
<view class="tab-item {{currentTab === 'profile' ? 'active' : ''}}" bindtap="onTabChange" data-tab="profile">
<image class="tab-icon" src="{{currentTab === 'profile' ? '/images/profile-active.png' : '/images/profile.png'}}"></image>
<text class="tab-text">我的</text>
</view>
</view>
</view>

@ -0,0 +1,270 @@
/* pages/main/main.wxss */
.page-container {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 100rpx;
}
/* 顶部导航栏 */
.header {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: linear-gradient(135deg, #4285F4 0%, #34A853 100%);
color: white;
}
.search-bar {
flex: 1;
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.9);
border-radius: 50rpx;
padding: 15rpx 25rpx;
margin-right: 20rpx;
}
.search-icon {
width: 32rpx;
height: 32rpx;
margin-right: 15rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
color: #333;
}
.user-info {
width: 80rpx;
height: 80rpx;
}
.avatar {
width: 100%;
height: 100%;
border-radius: 50%;
border: 3rpx solid white;
}
/* 功能导航 */
.nav-section {
background: white;
margin: 20rpx;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.function-group {
margin-bottom: 40rpx;
}
.function-group:last-child {
margin-bottom: 0;
}
.group-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
display: block;
padding-left: 10rpx;
border-left: 6rpx solid #4285F4;
}
.nav-grid {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
width: 150rpx;
margin-bottom: 20rpx;
}
.nav-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 15rpx;
}
.nav-text {
font-size: 24rpx;
color: #333;
text-align: center;
}
/* 推荐商品区域 */
.recommend-section {
background: white;
margin: 20rpx;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.section-header {
margin-bottom: 25rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.section-subtitle {
font-size: 24rpx;
color: #999;
}
.recommend-scroll {
white-space: nowrap;
}
.recommend-list {
display: inline-flex;
}
.product-card {
display: inline-block;
width: 280rpx;
margin-right: 20rpx;
background: #f8f9fa;
border-radius: 15rpx;
overflow: hidden;
}
.product-image {
width: 100%;
height: 200rpx;
}
.product-info {
padding: 20rpx;
}
.product-name {
font-size: 26rpx;
color: #333;
display: block;
margin-bottom: 10rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-price {
font-size: 28rpx;
color: #FF6B35;
font-weight: bold;
display: block;
margin-bottom: 8rpx;
}
.product-tag {
font-size: 20rpx;
color: #666;
background: #e9ecef;
padding: 4rpx 12rpx;
border-radius: 8rpx;
}
/* 热门求购 */
.wanted-section {
background: white;
margin: 20rpx;
border-radius: 20rpx;
padding: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.wanted-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.wanted-item {
background: #f8f9fa;
padding: 25rpx;
border-radius: 15rpx;
border-left: 6rpx solid #4285F4;
}
.wanted-title {
font-size: 28rpx;
color: #333;
font-weight: bold;
display: block;
margin-bottom: 10rpx;
}
.wanted-price {
font-size: 24rpx;
color: #FF6B35;
display: block;
margin-bottom: 8rpx;
}
.wanted-time {
font-size: 22rpx;
color: #999;
}
/* 底部导航栏 */
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
background: white;
border-top: 1rpx solid #e0e0e0;
padding: 15rpx 0;
z-index: 1000;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.tab-icon {
width: 48rpx;
height: 48rpx;
margin-bottom: 8rpx;
}
.tab-text {
font-size: 20rpx;
color: #999;
}
.tab-item.active .tab-text {
color: #4285F4;
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.nav-item {
width: 25%;
}
.product-card {
width: 250rpx;
}
}

@ -0,0 +1,423 @@
// pages/pricing/pricing.js
const cozeAPI = require('../../utils/coze-api.js');
Page({
/**
* 页面的初始数据
*/
data: {
// 图片相关
imagePath: '',
showResult: false,
isAnalyzing: false,
// 原价信息
originalPrice: '',
// AI定价结果
suggestedPrice: '0.00',
conditionLevel: '--',
marketRange: '--',
aiScore: '--',
analysisReport: '请先上传商品图片进行AI分析',
// AI生成的商品信息
productName: '--',
productCategory: '--',
productDescription: '请先进行AI分析以生成商品信息',
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('AI定价页面加载');
},
/**
* 选择图片
*/
onChooseImage() {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
maxDuration: 30,
camera: 'back',
success: (res) => {
const tempFilePath = res.tempFiles[0].tempFilePath;
this.setData({
imagePath: tempFilePath
});
// 自动开始AI分析
this.startAIAnalysis();
},
fail: (err) => {
console.error('选择图片失败:', err);
wx.showToast({
title: '选择图片失败',
icon: 'none'
});
}
});
},
/**
* 拍照上传
*/
onTakePhoto() {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['camera'],
maxDuration: 30,
camera: 'back',
success: (res) => {
const tempFilePath = res.tempFiles[0].tempFilePath;
this.setData({
imagePath: tempFilePath
});
// 自动开始AI分析
this.startAIAnalysis();
},
fail: (err) => {
console.error('拍照失败:', err);
wx.showToast({
title: '拍照失败',
icon: 'none'
});
}
});
},
/**
* 智能定价
*/
onAIPricing() {
if (!this.data.imagePath) {
wx.showToast({
title: '请先选择图片',
icon: 'none'
});
return;
}
if (!this.data.originalPrice) {
wx.showToast({
title: '请先输入商品原价',
icon: 'none'
});
return;
}
// 直接开始AI分析
this.startAIAnalysis();
},
/**
* 开始AI分析
*/
startAIAnalysis() {
if (!this.data.imagePath || !this.data.originalPrice) {
wx.showToast({
title: '请先上传图片并输入原价',
icon: 'none'
});
return;
}
this.setData({
isAnalyzing: true,
showResult: false
});
// 模拟AI分析过程
setTimeout(() => {
// 生成模拟的AI分析结果基于原价进行计算
const mockResults = this.generateMockAIPricing();
this.setData({
isAnalyzing: false,
showResult: true,
suggestedPrice: mockResults.price,
conditionLevel: mockResults.condition,
marketRange: mockResults.range,
aiScore: mockResults.score,
analysisReport: mockResults.report,
productName: mockResults.productName,
productCategory: mockResults.productCategory,
productDescription: mockResults.productDescription
});
wx.showToast({
title: 'AI分析完成',
icon: 'success'
});
}, 3000);
},
/**
* 生成模拟AI定价结果
*/
generateMockAIPricing() {
const originalPrice = parseFloat(this.data.originalPrice);
if (!originalPrice || originalPrice <= 0) {
return {
price: '0.00',
condition: '--',
range: '--',
score: '--',
report: '请输入有效的商品原价',
productName: '--',
productCategory: '--',
productDescription: '请输入有效的商品原价'
};
}
// 基于原价生成合理的二手价格范围
const depreciationRates = [0.3, 0.4, 0.5, 0.6, 0.7]; // 折旧率30%-70%
const conditionFactors = [0.9, 0.8, 0.7, 0.6, 0.5]; // 成色系数
const randomDepreciation = depreciationRates[Math.floor(Math.random() * depreciationRates.length)];
const randomCondition = conditionFactors[Math.floor(Math.random() * conditionFactors.length)];
// 计算建议价格
const basePrice = originalPrice * (1 - randomDepreciation);
const suggestedPrice = basePrice * randomCondition;
// 生成价格范围±10%
const minPrice = suggestedPrice * 0.9;
const maxPrice = suggestedPrice * 1.1;
// 成色描述
const conditions = ['全新', '95新', '9成新', '85新', '8成新', '7成新'];
const conditionIndex = Math.floor(randomCondition * 5);
// AI评分基于折旧率和成色
const aiScore = Math.floor(60 + (1 - randomDepreciation) * 20 + randomCondition * 20);
// 分析报告
const reports = [
`基于原价¥${originalPrice.toFixed(2)}分析,商品折旧率约${(randomDepreciation * 100).toFixed(0)}%,建议二手价格为¥${suggestedPrice.toFixed(2)}`,
`商品原价¥${originalPrice.toFixed(2)},当前成色${conditions[conditionIndex]},市场参考价格区间为¥${minPrice.toFixed(2)}-${maxPrice.toFixed(2)}`,
`AI分析原价¥${originalPrice.toFixed(2)}的商品,考虑到${conditions[conditionIndex]}的成色,建议定价为¥${suggestedPrice.toFixed(2)}`,
`根据原价¥${originalPrice.toFixed(2)}和商品状况评估,二手市场合理价格为¥${suggestedPrice.toFixed(2)}价格浮动范围±10%`
];
const randomReportIndex = Math.floor(Math.random() * reports.length);
// 生成商品信息
const productInfo = this.generateProductInfo(originalPrice, conditions[conditionIndex]);
return {
price: suggestedPrice.toFixed(2),
condition: conditions[conditionIndex],
range: `¥${minPrice.toFixed(2)}-${maxPrice.toFixed(2)}`,
score: aiScore,
report: reports[randomReportIndex],
...productInfo
};
},
/**
* 生成商品信息
*/
generateProductInfo(originalPrice, condition) {
// 商品类别库
const categories = [
{ name: '电子产品', items: ['iPhone 13', 'MacBook Pro', 'iPad Air', 'AirPods Pro', 'Apple Watch'] },
{ name: '服装鞋帽', items: ['Nike运动鞋', 'Adidas卫衣', '优衣库T恤', 'Zara外套', '李宁运动裤'] },
{ name: '图书文具', items: ['Python编程书', '英语四级词汇', '考研数学真题', '精美笔记本', '钢笔套装'] },
{ name: '生活用品', items: ['保温杯', '电动牙刷', '吹风机', '台灯', '收纳盒'] },
{ name: '运动户外', items: ['篮球', '羽毛球拍', '瑜伽垫', '登山包', '滑板'] },
{ name: '美妆个护', items: ['口红', '粉底液', '面膜', '洗发水', '香水'] }
];
// 根据原价范围选择类别
let selectedCategory;
if (originalPrice < 100) {
selectedCategory = categories[2]; // 图书文具
} else if (originalPrice < 500) {
selectedCategory = categories[3]; // 生活用品
} else if (originalPrice < 2000) {
selectedCategory = categories[4]; // 运动户外
} else {
selectedCategory = categories[0]; // 电子产品
}
const randomItemIndex = Math.floor(Math.random() * selectedCategory.items.length);
const productName = selectedCategory.items[randomItemIndex];
// 生成商品描述
const descriptions = [
`这是一款${condition}${productName},外观保存良好,功能正常使用。适合日常使用,性价比较高。`,
`${productName}${condition}成色,无明显划痕和损坏。经过测试各项功能正常,可以放心使用。`,
`商品为${condition}${productName},包装配件齐全。使用痕迹轻微,保养得当,值得推荐。`,
`这款${productName}保持${condition}状态,性能稳定可靠。适合学生或上班族使用,实用性强。`
];
const randomDescIndex = Math.floor(Math.random() * descriptions.length);
return {
productName: productName,
productCategory: selectedCategory.name,
productDescription: descriptions[randomDescIndex]
};
},
/**
* 原价输入
*/
onOriginalPriceInput(e) {
this.setData({
originalPrice: e.detail.value
});
},
/**
* 保存商品信息
*/
onSaveProduct() {
if (!this.validateForm()) {
return;
}
wx.showLoading({
title: '保存中...'
});
// 模拟保存过程
setTimeout(() => {
wx.hideLoading();
wx.showToast({
title: '保存成功',
icon: 'success'
});
// 返回主界面
setTimeout(() => {
wx.navigateBack();
}, 1500);
}, 2000);
},
/**
* 立即发布 - 跳转到发布商品页面
*/
onPublishProduct() {
// 验证是否有AI分析结果
if (!this.data.showResult) {
wx.showToast({
title: '请先进行AI分析',
icon: 'none'
});
return;
}
// 准备跳转参数
const params = {
imagePath: this.data.imagePath,
productName: this.data.productName,
productCategory: this.data.productCategory,
productDescription: this.data.productDescription,
originalPrice: this.data.originalPrice,
suggestedPrice: this.data.suggestedPrice,
priceRange: this.data.marketRange,
conditionLevel: this.data.conditionLevel,
aiScore: this.data.aiScore,
analysisReport: this.data.analysisReport
};
// 编码参数
const queryString = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
// 跳转到发布商品页面
wx.navigateTo({
url: `/pages/publish/publish?${queryString}`
});
},
/**
* 表单验证
*/
validateForm() {
if (!this.data.imagePath) {
wx.showToast({
title: '请上传商品图片',
icon: 'none'
});
return false;
}
if (!this.data.originalPrice || parseFloat(this.data.originalPrice) <= 0) {
wx.showToast({
title: '请输入有效的商品原价',
icon: 'none'
});
return false;
}
if (!this.data.showResult) {
wx.showToast({
title: '请先进行AI分析',
icon: 'none'
});
return false;
}
return true;
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

@ -0,0 +1,7 @@
{
"navigationBarTitleText": "AI智能定价",
"navigationBarBackgroundColor": "#4285F4",
"navigationBarTextStyle": "white",
"backgroundColor": "#f5f5f5",
"enablePullDownRefresh": false
}

@ -0,0 +1,137 @@
<!-- pages/pricing/pricing.wxml -->
<view class="page-container">
<!-- 商品上传模块 -->
<view class="upload-section">
<view class="section-header">
<text class="section-title">商品上传</text>
<text class="section-subtitle">上传商品图片进行AI智能定价</text>
</view>
<!-- 图片上传区域 -->
<view class="upload-area">
<view class="image-preview" bindtap="onChooseImage">
<view class="preview-content" wx:if="{{imagePath}}">
<image class="preview-image" src="{{imagePath}}" mode="aspectFit"></image>
<view class="preview-overlay">
<text class="preview-text">点击更换图片</text>
</view>
</view>
<view class="upload-placeholder" wx:else>
<image class="camera-icon" src="/images/边牧.png" mode="aspectFit"></image>
<text class="placeholder-text">点击上传商品图片</text>
<text class="placeholder-hint">支持 JPG、PNG 格式</text>
</view>
</view>
<!-- 原价输入区域 -->
<view class="original-price-section">
<view class="price-input-container">
<text class="price-label">商品原价</text>
<view class="price-input-group">
<text class="price-symbol">¥</text>
<input
class="price-input"
type="digit"
placeholder="0.00"
value="{{originalPrice}}"
bindinput="onOriginalPriceInput"
/>
</view>
</view>
</view>
<!-- 功能按钮区域 -->
<view class="button-group">
<button class="camera-btn" bindtap="onTakePhoto">
<image class="btn-icon" src="/images/边牧.png" mode="aspectFit"></image>
<text>拍照上传</text>
</button>
<button class="ai-pricing-btn" bindtap="onAIPricing" disabled="{{!imagePath || !originalPrice}}">
<image class="btn-icon" src="/images/边牧.png" mode="aspectFit"></image>
<text>智能定价</text>
</button>
</view>
</view>
</view>
<!-- AI定价结果及商品信息模块 -->
<view class="result-section" wx:if="{{showResult}}">
<!-- AI定价结果 -->
<view class="result-group">
<view class="section-header">
<text class="section-title">AI定价结果</text>
<text class="section-subtitle">基于图像分析和市场数据</text>
</view>
<view class="pricing-result">
<view class="price-display">
<text class="price-label">建议价格</text>
<text class="price-value">¥{{suggestedPrice}}</text>
</view>
<view class="price-details">
<view class="detail-item">
<text class="detail-label">商品成色</text>
<text class="detail-value">{{conditionLevel}}</text>
</view>
<view class="detail-item">
<text class="detail-label">市场参考</text>
<text class="detail-value">{{marketRange}}</text>
</view>
<view class="detail-item">
<text class="detail-label">AI评分</text>
<text class="detail-value">{{aiScore}}分</text>
</view>
</view>
<view class="ai-analysis">
<text class="analysis-title">AI分析报告</text>
<text class="analysis-content">{{analysisReport}}</text>
</view>
</view>
</view>
<!-- AI生成的商品信息 -->
<view class="product-info-group">
<view class="section-header">
<text class="section-title">AI智能识别</text>
<text class="section-subtitle">基于图像识别自动生成商品信息</text>
</view>
<view class="product-info">
<view class="info-item">
<text class="info-label">商品名称</text>
<text class="info-value">{{productName}}</text>
</view>
<view class="info-item">
<text class="info-label">商品类别</text>
<text class="info-value">{{productCategory}}</text>
</view>
<view class="info-item">
<text class="info-label">商品描述</text>
<text class="info-description">{{productDescription}}</text>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<button class="save-btn" bindtap="onSaveProduct">保存商品信息</button>
<button class="publish-btn" bindtap="onPublishProduct">立即发布</button>
</view>
</view>
<!-- 加载状态 -->
<view class="loading-section" wx:if="{{isAnalyzing}}">
<view class="loading-content">
<image class="loading-icon" src="/images/边牧.png" mode="aspectFit"></image>
<text class="loading-text">AI正在分析商品图片...</text>
<text class="loading-subtext">请稍候,这可能需要几秒钟</text>
</view>
</view>
</view>

@ -0,0 +1,400 @@
/* pages/pricing/pricing.wxss */
.page-container {
min-height: 100vh;
background-color: #f5f5f5;
padding: 20rpx;
}
/* 通用样式 */
.section-header {
margin-bottom: 30rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.section-subtitle {
font-size: 24rpx;
color: #999;
}
/* 商品上传模块 */
.upload-section {
background: white;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.upload-area {
display: flex;
flex-direction: column;
align-items: center;
}
.image-preview {
width: 300rpx;
height: 300rpx;
border: 4rpx dashed #ddd;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 30rpx;
background: #fafafa;
overflow: hidden;
position: relative;
}
/* 原价输入区域 */
.original-price-section {
width: 100%;
margin-bottom: 30rpx;
padding: 20rpx;
background: #f8f9fa;
border-radius: 15rpx;
border: 2rpx solid #e0e0e0;
}
.price-input-container {
display: flex;
align-items: center;
justify-content: space-between;
}
.price-input-container .price-label {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-right: 20rpx;
}
.price-input-container .price-input-group {
flex: 1;
display: flex;
align-items: center;
background: white;
border: 2rpx solid #4285F4;
border-radius: 10rpx;
padding: 15rpx 20rpx;
max-width: 250rpx;
}
.price-input-container .price-symbol {
font-size: 28rpx;
color: #4285F4;
font-weight: bold;
margin-right: 10rpx;
}
.price-input-container .price-input {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.image-preview:active {
background: #f0f0f0;
}
.preview-content {
width: 100%;
height: 100%;
position: relative;
}
.preview-image {
width: 100%;
height: 100%;
}
.preview-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.7);
padding: 20rpx;
text-align: center;
}
.preview-text {
color: white;
font-size: 24rpx;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40rpx;
}
.camera-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 20rpx;
opacity: 0.6;
}
.placeholder-text {
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.placeholder-hint {
font-size: 22rpx;
color: #999;
}
.button-group {
display: flex;
gap: 20rpx;
width: 100%;
justify-content: center;
}
.camera-btn, .ai-pricing-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 40rpx;
border-radius: 50rpx;
font-size: 26rpx;
border: none;
color: white;
}
.camera-btn {
background: #34A853;
}
.ai-pricing-btn {
background: linear-gradient(135deg, #FF6B35, #4285F4);
font-weight: bold;
box-shadow: 0 4rpx 15rpx rgba(255, 107, 53, 0.3);
}
.ai-pricing-btn[disabled] {
background: #ccc;
color: #999;
box-shadow: none;
}
.btn-icon {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
/* AI定价结果模块 */
.result-section {
background: white;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.result-group {
margin-bottom: 40rpx;
}
.pricing-result {
border: 2rpx dashed #4285F4;
border-radius: 15rpx;
padding: 30rpx;
background: #f8f9ff;
}
.price-display {
text-align: center;
margin-bottom: 30rpx;
padding-bottom: 30rpx;
border-bottom: 1rpx solid #e0e0e0;
}
.price-label {
font-size: 24rpx;
color: #666;
display: block;
margin-bottom: 10rpx;
}
.price-value {
font-size: 48rpx;
font-weight: bold;
color: #FF6B35;
}
.price-details {
display: flex;
justify-content: space-around;
margin-bottom: 30rpx;
}
.detail-item {
display: flex;
flex-direction: column;
align-items: center;
}
.detail-label {
font-size: 22rpx;
color: #999;
margin-bottom: 8rpx;
}
.detail-value {
font-size: 26rpx;
color: #333;
font-weight: bold;
}
.ai-analysis {
background: white;
border-radius: 10rpx;
padding: 20rpx;
border: 1rpx solid #e0e0e0;
}
.analysis-title {
font-size: 24rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
}
.analysis-content {
font-size: 22rpx;
color: #666;
line-height: 1.6;
}
/* AI生成的商品信息模块 */
.product-info-group {
margin-bottom: 40rpx;
}
.product-info {
background: #f8f9ff;
border-radius: 15rpx;
padding: 30rpx;
border: 2rpx solid #4285F4;
}
.info-item {
margin-bottom: 25rpx;
display: flex;
flex-direction: column;
}
.info-item:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 24rpx;
color: #666;
font-weight: bold;
margin-bottom: 8rpx;
}
.info-value {
font-size: 28rpx;
color: #333;
font-weight: bold;
background: white;
padding: 15rpx 20rpx;
border-radius: 8rpx;
border: 1rpx solid #e0e0e0;
}
.info-description {
font-size: 26rpx;
color: #333;
line-height: 1.6;
background: white;
padding: 20rpx;
border-radius: 8rpx;
border: 1rpx solid #e0e0e0;
min-height: 120rpx;
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
}
.save-btn, .publish-btn {
flex: 1;
padding: 25rpx;
border-radius: 50rpx;
font-size: 28rpx;
font-weight: bold;
border: none;
}
.save-btn {
background: #f8f9fa;
color: #333;
border: 2rpx solid #ddd;
}
.publish-btn {
background: linear-gradient(135deg, #4285F4, #34A853);
color: white;
}
/* 加载状态 */
.loading-section {
background: white;
border-radius: 20rpx;
padding: 60rpx 30rpx;
text-align: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
}
.loading-icon {
width: 100rpx;
height: 100rpx;
margin-bottom: 30rpx;
animation: rotate 2s linear infinite;
}
.loading-text {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
}
.loading-subtext {
font-size: 22rpx;
color: #999;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

@ -0,0 +1,263 @@
// pages/profile/profile.js
Page({
/**
* 页面的初始数据
*/
data: {
userInfo: {},
userStats: {
products: 0,
wanted: 0,
orders: 0,
favorites: 0
},
notificationEnabled: true
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.loadUserInfo();
this.loadUserStats();
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.loadUserInfo();
this.loadUserStats();
},
/**
* 加载用户信息
*/
loadUserInfo() {
const userInfo = wx.getStorageSync('userInfo') || {};
this.setData({
userInfo: userInfo
});
},
/**
* 加载用户统计数据
*/
loadUserStats() {
// 模拟从后端获取用户统计数据
const stats = wx.getStorageSync('userStats') || {
products: 12,
wanted: 3,
orders: 8,
favorites: 25
};
this.setData({
userStats: stats
});
},
/**
* 我的商品点击事件
*/
onMyProducts() {
wx.showToast({
title: '跳转到我的商品',
icon: 'none'
});
// 这里可以跳转到我的商品页面
},
/**
* 我的求购点击事件
*/
onMyWanted() {
wx.showToast({
title: '跳转到我的求购',
icon: 'none'
});
// 这里可以跳转到我的求购页面
},
/**
* 我的订单点击事件
*/
onMyOrders() {
wx.showToast({
title: '跳转到我的订单',
icon: 'none'
});
// 这里可以跳转到我的订单页面
},
/**
* 我的收藏点击事件
*/
onMyFavorites() {
wx.showToast({
title: '跳转到我的收藏',
icon: 'none'
});
// 这里可以跳转到我的收藏页面
},
/**
* 个人信息编辑
*/
onProfileEdit() {
wx.showModal({
title: '编辑个人信息',
content: '此功能正在开发中',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 安全设置
*/
onSecurity() {
wx.showModal({
title: '安全设置',
content: '此功能正在开发中',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 收货地址管理
*/
onAddress() {
wx.showModal({
title: '收货地址',
content: '此功能正在开发中',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 意见反馈
*/
onFeedback() {
wx.showModal({
title: '意见反馈',
content: '此功能正在开发中',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 消息通知开关
*/
onNotificationChange(e) {
const enabled = e.detail.value;
this.setData({
notificationEnabled: enabled
});
wx.showToast({
title: enabled ? '通知已开启' : '通知已关闭',
icon: 'success'
});
},
/**
* 隐私设置
*/
onPrivacy() {
wx.showModal({
title: '隐私设置',
content: '此功能正在开发中',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 关于我们
*/
onAbout() {
wx.showModal({
title: '关于SContact',
content: '版本: 1.0.0\n开发者: SContact团队\n联系方式: support@scontact.com',
showCancel: false,
confirmText: '知道了'
});
},
/**
* 退出登录
*/
onLogout() {
wx.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除登录信息
wx.removeStorageSync('userInfo');
wx.removeStorageSync('token');
wx.removeStorageSync('userStats');
// 显示退出成功提示
wx.showToast({
title: '退出成功',
icon: 'success',
duration: 1500
});
// 延迟跳转到登录页面
setTimeout(() => {
wx.redirectTo({
url: '/pages/index/index'
});
}, 1500);
}
}
});
},
/**
* 用户下拉刷新
*/
onPullDownRefresh() {
console.log('下拉刷新个人中心');
// 重新加载用户信息
this.loadUserInfo();
this.loadUserStats();
// 模拟刷新延迟
setTimeout(() => {
wx.stopPullDownRefresh();
wx.showToast({
title: '刷新成功',
icon: 'success'
});
}, 1000);
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉加载更多');
// 可以在这里加载更多数据
wx.showLoading({
title: '加载中...'
});
setTimeout(() => {
wx.hideLoading();
wx.showToast({
title: '没有更多数据了',
icon: 'none'
});
}, 1000);
}
})

@ -0,0 +1,8 @@
{
"navigationBarTitleText": "个人中心",
"navigationBarBackgroundColor": "#667eea",
"navigationBarTextStyle": "white",
"backgroundColor": "#f5f5f5",
"backgroundTextStyle": "dark",
"enablePullDownRefresh": true
}

@ -0,0 +1,111 @@
<!--pages/profile/profile.wxml-->
<view class="page-container">
<!-- 顶部用户信息区域 -->
<view class="user-header">
<view class="user-avatar-section">
<image class="user-avatar" src="{{userInfo.avatar || '/images/default-avatar.png'}}" mode="aspectFit"></image>
<view class="user-info">
<text class="user-name">{{userInfo.nickName || '未设置昵称'}}</text>
<text class="user-id">ID: {{userInfo.id || '未设置'}}</text>
<text class="user-level">会员等级: {{userInfo.level || '普通会员'}}</text>
</view>
</view>
<view class="user-stats">
<view class="stat-item" bindtap="onMyProducts">
<text class="stat-number">{{userStats.products || 0}}</text>
<text class="stat-label">我的商品</text>
</view>
<view class="stat-item" bindtap="onMyWanted">
<text class="stat-number">{{userStats.wanted || 0}}</text>
<text class="stat-label">我的求购</text>
</view>
<view class="stat-item" bindtap="onMyOrders">
<text class="stat-number">{{userStats.orders || 0}}</text>
<text class="stat-label">我的订单</text>
</view>
</view>
</view>
<!-- 功能菜单区域 -->
<view class="menu-section">
<view class="menu-group">
<text class="group-title">交易管理</text>
<view class="menu-list">
<view class="menu-item" bindtap="onMyProducts">
<image class="menu-icon" src="/images/product.png" mode="aspectFit"></image>
<text class="menu-text">我的商品</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onMyWanted">
<image class="menu-icon" src="/images/wanted.png" mode="aspectFit"></image>
<text class="menu-text">我的求购</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onMyOrders">
<image class="menu-icon" src="/images/order.png" mode="aspectFit"></image>
<text class="menu-text">我的订单</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onMyFavorites">
<image class="menu-icon" src="/images/favorite.png" mode="aspectFit"></image>
<text class="menu-text">我的收藏</text>
<text class="menu-arrow">></text>
</view>
</view>
</view>
<view class="menu-group">
<text class="group-title">账户设置</text>
<view class="menu-list">
<view class="menu-item" bindtap="onProfileEdit">
<image class="menu-icon" src="/images/profile.png" mode="aspectFit"></image>
<text class="menu-text">个人信息</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onSecurity">
<image class="menu-icon" src="/images/security.png" mode="aspectFit"></image>
<text class="menu-text">安全设置</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onAddress">
<image class="menu-icon" src="/images/address.png" mode="aspectFit"></image>
<text class="menu-text">收货地址</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onFeedback">
<image class="menu-icon" src="/images/feedback.png" mode="aspectFit"></image>
<text class="menu-text">意见反馈</text>
<text class="menu-arrow">></text>
</view>
</view>
</view>
<view class="menu-group">
<text class="group-title">系统设置</text>
<view class="menu-list">
<view class="menu-item" bindtap="onNotification">
<image class="menu-icon" src="/images/notification.png" mode="aspectFit"></image>
<text class="menu-text">消息通知</text>
<view class="menu-switch">
<switch checked="{{notificationEnabled}}" bindchange="onNotificationChange" />
</view>
</view>
<view class="menu-item" bindtap="onPrivacy">
<image class="menu-icon" src="/images/privacy.png" mode="aspectFit"></image>
<text class="menu-text">隐私设置</text>
<text class="menu-arrow">></text>
</view>
<view class="menu-item" bindtap="onAbout">
<image class="menu-icon" src="/images/about.png" mode="aspectFit"></image>
<text class="menu-text">关于我们</text>
<text class="menu-arrow">></text>
</view>
</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="action-section">
<button class="logout-btn" bindtap="onLogout">退出登录</button>
</view>
</view>

@ -0,0 +1,173 @@
/* pages/profile/profile.wxss */
.page-container {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 100rpx;
}
/* 顶部用户信息区域 */
.user-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40rpx 30rpx;
color: white;
}
.user-avatar-section {
display: flex;
align-items: center;
margin-bottom: 40rpx;
}
.user-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 4rpx solid rgba(255, 255, 255, 0.3);
margin-right: 30rpx;
}
.user-info {
flex: 1;
}
.user-name {
font-size: 36rpx;
font-weight: bold;
display: block;
margin-bottom: 10rpx;
}
.user-id, .user-level {
font-size: 24rpx;
opacity: 0.9;
display: block;
margin-bottom: 5rpx;
}
.user-stats {
display: flex;
justify-content: space-around;
text-align: center;
}
.stat-item {
padding: 20rpx 0;
}
.stat-number {
font-size: 32rpx;
font-weight: bold;
display: block;
margin-bottom: 10rpx;
}
.stat-label {
font-size: 24rpx;
opacity: 0.9;
}
/* 功能菜单区域 */
.menu-section {
padding: 30rpx;
}
.menu-group {
background: white;
border-radius: 20rpx;
margin-bottom: 30rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.group-title {
display: block;
padding: 30rpx 30rpx 20rpx;
font-size: 28rpx;
font-weight: bold;
color: #333;
border-bottom: 1rpx solid #f0f0f0;
}
.menu-list {
padding: 0;
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f8f8f8;
transition: background-color 0.3s;
}
.menu-item:active {
background-color: #f8f8f8;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.menu-text {
flex: 1;
font-size: 28rpx;
color: #333;
}
.menu-arrow {
font-size: 24rpx;
color: #999;
}
.menu-switch {
margin-left: auto;
}
/* 底部操作按钮 */
.action-section {
padding: 30rpx;
}
.logout-btn {
width: 100%;
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
color: white;
border: none;
border-radius: 50rpx;
padding: 30rpx;
font-size: 32rpx;
font-weight: bold;
box-shadow: 0 8rpx 25rpx rgba(255, 107, 107, 0.3);
}
.logout-btn:active {
transform: translateY(2rpx);
box-shadow: 0 4rpx 15rpx rgba(255, 107, 107, 0.3);
}
/* 响应式调整 */
@media (max-width: 750rpx) {
.user-header {
padding: 30rpx 20rpx;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
}
.menu-section {
padding: 20rpx;
}
.menu-item {
padding: 25rpx;
}
}

@ -0,0 +1,346 @@
// pages/publish/publish.js
Page({
/**
* 页面的初始数据
*/
data: {
// 页面来源标识
fromAIPricing: false,
// 商品基本信息
productImage: '',
productName: '',
productCategory: '',
productDescription: '',
categories: ['电子产品', '图书文具', '服装鞋帽', '家居用品', '运动户外', '美妆个护', '其他'],
categoryIndex: 0,
// 价格信息
originalPrice: '',
suggestedPrice: '',
priceRange: '',
salePrice: '',
// 商品状况
conditionLevel: '',
aiScore: '',
// AI分析报告
analysisReport: '',
// 发布设置
contactInfo: '',
transactionMethods: ['面交', '快递', '自提'],
selectedMethods: [],
// 发布状态
isPublishing: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('发布商品页面加载,接收参数:', options);
// 从页面参数中获取数据
if (options && Object.keys(options).length > 0) {
// 从AI定价页面跳转带完整参数
this.setData({
fromAIPricing: true,
productImage: options.imagePath || '',
productName: options.productName || '',
productCategory: options.productCategory || '',
productDescription: options.productDescription || '',
originalPrice: options.originalPrice || '',
suggestedPrice: options.suggestedPrice || '',
priceRange: options.priceRange || '',
conditionLevel: options.conditionLevel || '',
aiScore: options.aiScore || '',
analysisReport: options.analysisReport || ''
});
// 如果传递了建议价格,设置为默认售价
if (options.suggestedPrice) {
this.setData({
salePrice: options.suggestedPrice
});
}
// 显示从AI定价跳转的提示
wx.showToast({
title: 'AI分析结果已加载',
icon: 'success',
duration: 1500
});
} else {
// 从主界面直接进入,显示空表单
this.setData({
fromAIPricing: false,
productName: '',
productCategory: '',
productDescription: '',
salePrice: ''
});
// 显示直接发布的提示
wx.showToast({
title: '请填写商品信息',
icon: 'none',
duration: 1500
});
}
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('发布商品页面显示');
},
/**
* 商品名称输入事件
*/
onProductNameInput(e) {
this.setData({
productName: e.detail.value
});
},
/**
* 商品类别选择事件
*/
onCategoryChange(e) {
const index = e.detail.value;
this.setData({
categoryIndex: index,
productCategory: this.data.categories[index]
});
},
/**
* 商品描述输入事件
*/
onDescriptionInput(e) {
this.setData({
productDescription: e.detail.value
});
},
/**
* 上传商品图片
*/
onUploadImage() {
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths;
if (tempFilePaths.length > 0) {
this.setData({
productImage: tempFilePaths[0]
});
wx.showToast({
title: '图片上传成功',
icon: 'success'
});
}
},
fail: (error) => {
console.error('选择图片失败:', error);
wx.showToast({
title: '图片选择失败',
icon: 'none'
});
}
});
},
/**
* 售价输入
*/
onSalePriceInput(e) {
const value = e.detail.value;
this.setData({
salePrice: value
});
},
/**
* 联系方式输入
*/
onContactInput(e) {
const value = e.detail.value;
this.setData({
contactInfo: value
});
},
/**
* 交易方式选择
*/
onTradeMethodChange(e) {
const index = parseInt(e.detail.value);
this.setData({
tradeMethodIndex: index
});
},
/**
* 验证表单数据
*/
validateForm() {
const {
fromAIPricing,
productName,
productCategory,
productDescription,
salePrice,
contactInfo,
selectedMethods
} = this.data;
// 验证商品名称
if (!productName || productName.trim() === '') {
wx.showToast({
title: '请输入商品名称',
icon: 'none'
});
return false;
}
// 验证商品类别
if (!productCategory || productCategory.trim() === '') {
wx.showToast({
title: '请选择商品类别',
icon: 'none'
});
return false;
}
// 验证商品描述
if (!productDescription || productDescription.trim() === '') {
wx.showToast({
title: '请输入商品描述',
icon: 'none'
});
return false;
}
// 验证售价
if (!salePrice || isNaN(parseFloat(salePrice)) || parseFloat(salePrice) <= 0) {
wx.showToast({
title: '请输入有效的售价',
icon: 'none'
});
return false;
}
// 验证联系方式
if (!contactInfo || contactInfo.trim() === '') {
wx.showToast({
title: '请输入联系方式',
icon: 'none'
});
return false;
}
// 验证交易方式(至少选择一种)
if (selectedMethods.length === 0) {
wx.showToast({
title: '请至少选择一种交易方式',
icon: 'none'
});
return false;
}
// 如果是直接发布模式,还需要验证商品图片
if (!fromAIPricing && (!this.data.productImage || this.data.productImage.trim() === '')) {
wx.showToast({
title: '请上传商品图片',
icon: 'none'
});
return false;
}
return true;
},
/**
* 发布商品
*/
onPublish() {
// 验证数据
if (!this.validatePublishData()) {
return;
}
// 设置发布状态
this.setData({
isPublishing: true
});
// 显示发布中提示
wx.showLoading({
title: '发布中...'
});
// 模拟发布过程
setTimeout(() => {
// 模拟发布成功
this.setData({
isPublishing: false
});
wx.hideLoading();
// 显示发布成功提示
wx.showToast({
title: '发布成功',
icon: 'success',
duration: 2000
});
// 延迟跳转到主页面
setTimeout(() => {
wx.switchTab({
url: '/pages/main/main'
});
}, 1500);
}, 2000);
},
/**
* 返回修改
*/
onBack() {
wx.navigateBack({
delta: 1
});
},
/**
* 分享功能
*/
onShareAppMessage() {
return {
title: '我在二手市场发布了商品:' + this.data.productName,
path: '/pages/main/main',
imageUrl: this.data.productImage
};
},
/**
* 用户点击右上角分享
*/
onShareTimeline() {
return {
title: '我在二手市场发布了商品:' + this.data.productName,
imageUrl: this.data.productImage
};
}
})

@ -0,0 +1,6 @@
{
"usingComponents": {},
"navigationBarTitleText": "发布商品",
"navigationBarBackgroundColor": "#4285F4",
"navigationBarTextStyle": "white"
}

@ -0,0 +1,195 @@
<!--pages/publish/publish.wxml-->
<view class="publish-container">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">发布商品</text>
<text class="page-subtitle">确认商品信息并发布到二手市场</text>
</view>
<!-- 商品图片预览 -->
<view class="section">
<view class="section-header">
<text class="section-title">商品图片</text>
<button
type="primary"
size="mini"
bindtap="onUploadImage"
class="upload-btn"
wx:if="{{!fromAIPricing}}"
>
上传图片
</button>
</view>
<view class="image-preview">
<image
src="{{productImage}}"
mode="aspectFill"
class="product-image"
wx:if="{{productImage}}"
/>
<view class="no-image" wx:else>
<text class="no-image-text">暂无图片</text>
</view>
</view>
</view>
<!-- 商品基本信息 -->
<view class="section">
<view class="section-header">
<text class="section-title">商品信息</text>
</view>
<view class="info-group">
<view class="info-item">
<text class="info-label">商品名称</text>
<text class="info-value" wx:if="{{fromAIPricing}}">{{productName}}</text>
<input
type="text"
placeholder="请输入商品名称"
value="{{productName}}"
bindinput="onProductNameInput"
class="info-input"
placeholder-class="placeholder"
wx:else
/>
</view>
<view class="info-item">
<text class="info-label">商品类别</text>
<text class="info-value" wx:if="{{fromAIPricing}}">{{productCategory}}</text>
<picker
range="{{categories}}"
value="{{categoryIndex}}"
bindchange="onCategoryChange"
class="category-picker"
wx:else
>
<view class="picker-display">
<text class="picker-text">{{categories[categoryIndex] || '请选择商品类别'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="info-item">
<text class="info-label">商品描述</text>
<text class="info-value description-text" wx:if="{{fromAIPricing}}">{{productDescription}}</text>
<textarea
placeholder="请输入商品描述"
value="{{productDescription}}"
bindinput="onDescriptionInput"
class="description-textarea"
placeholder-class="placeholder"
maxlength="200"
auto-height
wx:else
/>
</view>
</view>
</view>
<!-- 价格信息 -->
<view class="section">
<view class="section-header">
<text class="section-title">价格信息</text>
</view>
<view class="price-group">
<view class="price-item">
<text class="price-label">原价</text>
<text class="price-value original-price">¥{{originalPrice}}</text>
</view>
<view class="price-item">
<text class="price-label">AI建议价格</text>
<text class="price-value suggested-price">¥{{suggestedPrice}}</text>
</view>
<view class="price-item">
<text class="price-label">价格范围</text>
<text class="price-value range-price">{{priceRange}}</text>
</view>
</view>
</view>
<!-- 商品状况 -->
<view class="section">
<view class="section-header">
<text class="section-title">商品状况</text>
</view>
<view class="condition-group">
<view class="condition-item">
<text class="condition-label">成色</text>
<text class="condition-value">{{conditionLevel}}</text>
</view>
<view class="condition-item">
<text class="condition-label">AI评分</text>
<text class="condition-value score">{{aiScore}}分</text>
</view>
</view>
</view>
<!-- AI分析报告 -->
<view class="section" wx:if="{{analysisReport}}">
<view class="section-header">
<text class="section-title">AI分析报告</text>
</view>
<view class="report-container">
<text class="report-text">{{analysisReport}}</text>
</view>
</view>
<!-- 发布设置 -->
<view class="section">
<view class="section-header">
<text class="section-title">发布设置</text>
</view>
<view class="publish-settings">
<view class="setting-item">
<text class="setting-label">商品售价</text>
<view class="price-input-container">
<text class="currency-symbol">¥</text>
<input
type="digit"
placeholder="请输入售价"
value="{{salePrice}}"
bindinput="onSalePriceInput"
class="price-input"
placeholder-class="placeholder"
/>
</view>
</view>
<view class="setting-item">
<text class="setting-label">联系方式</text>
<input
type="text"
placeholder="请输入手机号或微信号"
value="{{contactInfo}}"
bindinput="onContactInput"
class="contact-input"
placeholder-class="placeholder"
/>
</view>
<view class="setting-item">
<text class="setting-label">交易方式</text>
<picker
range="{{tradeMethods}}"
value="{{tradeMethodIndex}}"
bindchange="onTradeMethodChange"
class="picker"
>
<view class="picker-display">
<text class="picker-text">{{tradeMethods[tradeMethodIndex]}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
</view>
</view>
<!-- 发布按钮 -->
<view class="publish-actions">
<button
class="publish-btn {{isPublishing ? 'disabled' : ''}}"
bindtap="onPublish"
disabled="{{isPublishing}}"
>
{{isPublishing ? '发布中...' : '确认发布'}}
</button>
<button class="back-btn" bindtap="onBack">返回修改</button>
</view>
</view>

@ -0,0 +1,362 @@
/* pages/publish/publish.wxss */
.publish-container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
/* 页面标题 */
.page-header {
text-align: center;
margin-bottom: 40rpx;
}
.page-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.page-subtitle {
font-size: 24rpx;
color: #666;
}
/* 通用区块样式 */
.section {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
}
.section-header {
margin-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
padding-bottom: 15rpx;
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
/* 商品图片预览 */
.image-preview {
display: flex;
justify-content: center;
align-items: center;
height: 300rpx;
background-color: #f8f9fa;
border-radius: 12rpx;
border: 2rpx dashed #ddd;
}
.product-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.no-image {
text-align: center;
}
.no-image-text {
font-size: 24rpx;
color: #999;
}
/* 商品信息 */
.info-group {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.info-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
.info-value {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
word-break: break-all;
}
.description-text {
line-height: 1.6;
}
/* 输入控件样式 */
.info-input {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
border: none;
outline: none;
background: transparent;
}
.category-picker {
flex: 1;
}
.picker-display {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
}
.picker-text {
font-size: 28rpx;
color: #333;
}
.picker-arrow {
font-size: 24rpx;
color: #999;
}
.description-textarea {
font-size: 28rpx;
color: #333;
flex: 1;
min-height: 120rpx;
border: none;
outline: none;
background: transparent;
line-height: 1.6;
}
.placeholder {
color: #ccc;
}
/* 价格信息 */
.price-group {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.price-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.price-label {
font-size: 26rpx;
color: #666;
}
.price-value {
font-size: 28rpx;
font-weight: bold;
}
.original-price {
color: #999;
text-decoration: line-through;
}
.suggested-price {
color: #ff6b35;
}
.range-price {
color: #4285f4;
}
/* 商品状况 */
.condition-group {
display: flex;
gap: 40rpx;
}
.condition-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.condition-label {
font-size: 24rpx;
color: #666;
margin-bottom: 10rpx;
}
.condition-value {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.score {
color: #ff6b35;
}
/* AI分析报告 */
.report-container {
background: #f8f9ff;
border: 1rpx solid #e0e7ff;
border-radius: 12rpx;
padding: 20rpx;
}
.report-text {
font-size: 24rpx;
color: #333;
line-height: 1.6;
}
/* 发布设置 */
.publish-settings {
display: flex;
flex-direction: column;
gap: 25rpx;
}
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.setting-label {
font-size: 26rpx;
color: #666;
width: 140rpx;
flex-shrink: 0;
}
.price-input-container {
display: flex;
align-items: center;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
height: 70rpx;
flex: 1;
}
.currency-symbol {
font-size: 26rpx;
color: #333;
margin-right: 10rpx;
}
.price-input {
flex: 1;
font-size: 26rpx;
color: #333;
height: 100%;
}
.contact-input {
flex: 1;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
height: 70rpx;
font-size: 26rpx;
color: #333;
}
.picker {
flex: 1;
}
.picker-display {
display: flex;
justify-content: space-between;
align-items: center;
background: #f8f9fa;
border-radius: 8rpx;
padding: 0 20rpx;
height: 70rpx;
}
.picker-text {
font-size: 26rpx;
color: #333;
}
.picker-arrow {
font-size: 20rpx;
color: #999;
}
.placeholder {
color: #ccc;
}
/* 发布按钮 */
.publish-actions {
margin-top: 40rpx;
display: flex;
flex-direction: column;
gap: 20rpx;
}
.publish-btn {
background: linear-gradient(135deg, #FF6B35, #4285F4);
color: white;
border: none;
border-radius: 50rpx;
height: 80rpx;
font-size: 28rpx;
font-weight: bold;
box-shadow: 0 4rpx 20rpx rgba(255, 107, 53, 0.3);
}
.publish-btn.disabled {
background: #ccc;
box-shadow: none;
}
.back-btn {
background: white;
color: #666;
border: 1rpx solid #ddd;
border-radius: 50rpx;
height: 80rpx;
font-size: 28rpx;
}
/* 响应式调整 */
@media (max-width: 750rpx) {
.publish-container {
padding: 15rpx;
}
.section {
padding: 20rpx;
}
.condition-group {
flex-direction: column;
gap: 20rpx;
}
}

@ -0,0 +1,328 @@
// pages/purchase/purchase.js
Page({
/**
* 页面的初始数据
*/
data: {
// 求购商品信息
productName: '',
categoryIndex: 0,
categories: ['电子产品', '服装鞋帽', '家居用品', '图书文具', '运动户外', '美妆个护', '母婴玩具', '其他'],
purchaseDescription: '',
// 求购要求
expectedPrice: '',
conditionIndex: 0,
conditionLevels: ['全新', '95新', '9成新', '8成新', '7成新', '不限'],
expectedBrand: '',
expectedModel: '',
// 求购时间
expectedDate: '',
validityIndex: 0,
validityPeriods: ['3天', '7天', '15天', '30天', '长期有效'],
// 联系方式
contactName: '',
contactPhone: '',
contactWechat: '',
tradeMethodIndex: 0,
tradeMethods: ['面交', '快递', '均可'],
// 发布状态
isPublishing: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('求购页面加载', options);
// 可以在这里初始化一些数据,比如从缓存中读取用户信息
},
/**
* 商品名称输入
*/
onProductNameInput(e) {
this.setData({
productName: e.detail.value
});
},
/**
* 商品类别选择
*/
onCategoryChange(e) {
this.setData({
categoryIndex: parseInt(e.detail.value)
});
},
/**
* 求购描述输入
*/
onDescriptionInput(e) {
this.setData({
purchaseDescription: e.detail.value
});
},
/**
* 期望价格输入
*/
onExpectedPriceInput(e) {
this.setData({
expectedPrice: e.detail.value
});
},
/**
* 成色要求选择
*/
onConditionChange(e) {
this.setData({
conditionIndex: parseInt(e.detail.value)
});
},
/**
* 期望品牌输入
*/
onBrandInput(e) {
this.setData({
expectedBrand: e.detail.value
});
},
/**
* 期望型号输入
*/
onModelInput(e) {
this.setData({
expectedModel: e.detail.value
});
},
/**
* 期望到货时间选择
*/
onDateChange(e) {
this.setData({
expectedDate: e.detail.value
});
},
/**
* 有效期选择
*/
onValidityChange(e) {
this.setData({
validityIndex: parseInt(e.detail.value)
});
},
/**
* 联系人姓名输入
*/
onContactNameInput(e) {
this.setData({
contactName: e.detail.value
});
},
/**
* 手机号码输入
*/
onContactPhoneInput(e) {
this.setData({
contactPhone: e.detail.value
});
},
/**
* 微信号输入
*/
onWechatInput(e) {
this.setData({
contactWechat: e.detail.value
});
},
/**
* 交易方式选择
*/
onTradeMethodChange(e) {
this.setData({
tradeMethodIndex: parseInt(e.detail.value)
});
},
/**
* 表单验证
*/
validateForm() {
const { productName, contactName, contactPhone } = this.data;
if (!productName.trim()) {
wx.showToast({
title: '请输入商品名称',
icon: 'none'
});
return false;
}
if (!contactName.trim()) {
wx.showToast({
title: '请输入联系人姓名',
icon: 'none'
});
return false;
}
if (!contactPhone.trim()) {
wx.showToast({
title: '请输入手机号码',
icon: 'none'
});
return false;
}
// 手机号格式验证
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(contactPhone)) {
wx.showToast({
title: '请输入正确的手机号码',
icon: 'none'
});
return false;
}
return true;
},
/**
* 发布求购
*/
onPublish() {
if (this.data.isPublishing) return;
if (!this.validateForm()) return;
this.setData({
isPublishing: true
});
// 模拟发布过程
wx.showLoading({
title: '发布中...'
});
// 构建求购数据
const purchaseData = {
productName: this.data.productName,
category: this.data.categories[this.data.categoryIndex],
description: this.data.purchaseDescription,
expectedPrice: this.data.expectedPrice,
condition: this.data.conditionLevels[this.data.conditionIndex],
brand: this.data.expectedBrand,
model: this.data.expectedModel,
expectedDate: this.data.expectedDate,
validity: this.data.validityPeriods[this.data.validityIndex],
contactName: this.data.contactName,
contactPhone: this.data.contactPhone,
wechat: this.data.contactWechat,
tradeMethod: this.data.tradeMethods[this.data.tradeMethodIndex],
publishTime: new Date().toISOString(),
status: 'active'
};
console.log('发布求购数据:', purchaseData);
// 模拟网络请求
setTimeout(() => {
wx.hideLoading();
// 发布成功
wx.showToast({
title: '发布成功!',
icon: 'success',
duration: 2000
});
this.setData({
isPublishing: false
});
// 发布成功后返回上一页或跳转到求购列表
setTimeout(() => {
wx.navigateBack();
}, 1500);
}, 2000);
},
/**
* 取消发布
*/
onBack() {
wx.showModal({
title: '确认取消',
content: '确定要取消发布求购吗?已填写的信息将不会保存。',
success: (res) => {
if (res.confirm) {
wx.navigateBack();
}
}
});
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "发布求购",
"navigationBarBackgroundColor": "#667eea",
"navigationBarTextStyle": "white",
"backgroundColor": "#f5f5f5",
"backgroundTextStyle": "light"
}

@ -0,0 +1,219 @@
<!-- 发布求购页面 -->
<view class="purchase-container">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">发布求购</text>
<text class="page-subtitle">发布您的求购需求,让卖家主动联系您</text>
</view>
<!-- 求购商品信息 -->
<view class="section">
<view class="section-header">
<text class="section-title">求购商品信息</text>
</view>
<view class="info-group">
<view class="info-item">
<text class="info-label">商品名称</text>
<input
type="text"
placeholder="请输入您想购买的商品名称"
value="{{productName}}"
bindinput="onProductNameInput"
class="info-input"
placeholder-class="placeholder"
/>
</view>
<view class="info-item">
<text class="info-label">商品类别</text>
<picker
range="{{categories}}"
value="{{categoryIndex}}"
bindchange="onCategoryChange"
class="category-picker"
>
<view class="picker-display">
<text class="picker-text">{{categories[categoryIndex] || '请选择商品类别'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="info-item">
<text class="info-label">求购描述</text>
<textarea
placeholder="请详细描述您的求购需求(品牌、型号、规格等)"
value="{{purchaseDescription}}"
bindinput="onDescriptionInput"
class="description-textarea"
placeholder-class="placeholder"
maxlength="300"
auto-height
/>
</view>
</view>
</view>
<!-- 求购要求 -->
<view class="section">
<view class="section-header">
<text class="section-title">求购要求</text>
</view>
<view class="requirement-group">
<view class="requirement-item">
<text class="requirement-label">期望价格</text>
<view class="price-input-container">
<text class="currency-symbol">¥</text>
<input
type="digit"
placeholder="请输入期望价格"
value="{{expectedPrice}}"
bindinput="onExpectedPriceInput"
class="price-input"
placeholder-class="placeholder"
/>
</view>
</view>
<view class="requirement-item">
<text class="requirement-label">成色要求</text>
<picker
range="{{conditionLevels}}"
value="{{conditionIndex}}"
bindchange="onConditionChange"
class="condition-picker"
>
<view class="picker-display">
<text class="picker-text">{{conditionLevels[conditionIndex] || '请选择成色要求'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="requirement-item">
<text class="requirement-label">期望品牌</text>
<input
type="text"
placeholder="请输入期望品牌(可选)"
value="{{expectedBrand}}"
bindinput="onBrandInput"
class="brand-input"
placeholder-class="placeholder"
/>
</view>
<view class="requirement-item">
<text class="requirement-label">期望型号</text>
<input
type="text"
placeholder="请输入期望型号(可选)"
value="{{expectedModel}}"
bindinput="onModelInput"
class="model-input"
placeholder-class="placeholder"
/>
</view>
</view>
</view>
<!-- 求购时间 -->
<view class="section">
<view class="section-header">
<text class="section-title">求购时间</text>
</view>
<view class="time-group">
<view class="time-item">
<text class="time-label">期望到货时间</text>
<picker
mode="date"
value="{{expectedDate}}"
bindchange="onDateChange"
class="date-picker"
>
<view class="picker-display">
<text class="picker-text">{{expectedDate || '请选择期望到货时间'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="time-item">
<text class="time-label">求购有效期</text>
<picker
range="{{validityPeriods}}"
value="{{validityIndex}}"
bindchange="onValidityChange"
class="validity-picker"
>
<view class="picker-display">
<text class="picker-text">{{validityPeriods[validityIndex] || '请选择有效期'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
</view>
</view>
<!-- 联系方式 -->
<view class="section">
<view class="section-header">
<text class="section-title">联系方式</text>
</view>
<view class="contact-group">
<view class="contact-item">
<text class="contact-label">联系人</text>
<input
type="text"
placeholder="请输入您的姓名"
value="{{contactName}}"
bindinput="onContactNameInput"
class="contact-input"
placeholder-class="placeholder"
/>
</view>
<view class="contact-item">
<text class="contact-label">手机号码</text>
<input
type="number"
placeholder="请输入手机号码"
value="{{contactPhone}}"
bindinput="onContactPhoneInput"
class="phone-input"
placeholder-class="placeholder"
maxlength="11"
/>
</view>
<view class="contact-item">
<text class="contact-label">微信号</text>
<input
type="text"
placeholder="请输入微信号(可选)"
value="{{contactWechat}}"
bindinput="onWechatInput"
class="wechat-input"
placeholder-class="placeholder"
/>
</view>
<view class="contact-item">
<text class="contact-label">交易方式</text>
<picker
range="{{tradeMethods}}"
value="{{tradeMethodIndex}}"
bindchange="onTradeMethodChange"
class="trade-picker"
>
<view class="picker-display">
<text class="picker-text">{{tradeMethods[tradeMethodIndex] || '请选择交易方式'}}</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
</view>
</view>
<!-- 发布按钮 -->
<view class="publish-actions">
<button
class="publish-btn {{isPublishing ? 'disabled' : ''}}"
bindtap="onPublish"
disabled="{{isPublishing}}"
>
{{isPublishing ? '发布中...' : '确认发布求购'}}
</button>
<button class="back-btn" bindtap="onBack">取消</button>
</view>
</view>

@ -0,0 +1,320 @@
/* 发布求购页面样式 */
.purchase-container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
/* 页面标题 */
.page-header {
text-align: center;
margin-bottom: 40rpx;
}
.page-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 10rpx;
}
.page-subtitle {
font-size: 24rpx;
color: #666;
}
/* 通用区块样式 */
.section {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
}
.section-header {
margin-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
padding-bottom: 15rpx;
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
/* 求购信息组 */
.info-group {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.info-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
.info-value {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
word-break: break-all;
}
/* 输入控件样式 */
.info-input {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
border: none;
outline: none;
background: transparent;
}
.category-picker {
flex: 1;
}
.picker-display {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
}
.picker-text {
font-size: 28rpx;
color: #333;
}
.picker-arrow {
font-size: 24rpx;
color: #999;
}
.description-textarea {
font-size: 28rpx;
color: #333;
flex: 1;
min-height: 120rpx;
border: none;
outline: none;
background: transparent;
line-height: 1.6;
}
.placeholder {
color: #ccc;
}
/* 求购要求组 */
.requirement-group {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.requirement-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.requirement-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
/* 价格输入容器 */
.price-input-container {
display: flex;
align-items: center;
flex: 1;
justify-content: flex-end;
}
.currency-symbol {
font-size: 28rpx;
color: #333;
margin-right: 10rpx;
}
.price-input {
font-size: 28rpx;
color: #333;
border: none;
outline: none;
background: transparent;
text-align: right;
width: 200rpx;
}
.condition-picker {
flex: 1;
}
.brand-input, .model-input {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
border: none;
outline: none;
background: transparent;
}
/* 时间组 */
.time-group {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.time-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.time-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
.date-picker, .validity-picker {
flex: 1;
}
/* 联系方式组 */
.contact-group {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.contact-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.contact-label {
font-size: 28rpx;
color: #666;
min-width: 120rpx;
}
.contact-input, .phone-input, .wechat-input {
font-size: 28rpx;
color: #333;
flex: 1;
text-align: right;
border: none;
outline: none;
background: transparent;
}
.trade-picker {
flex: 1;
}
/* 发布按钮 */
.publish-actions {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.publish-btn {
flex: 2;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 50rpx;
padding: 25rpx;
font-size: 32rpx;
font-weight: bold;
box-shadow: 0 4rpx 20rpx rgba(102, 126, 234, 0.3);
}
.publish-btn.disabled {
background: #ccc;
box-shadow: none;
}
.back-btn {
flex: 1;
background: #f8f9fa;
color: #666;
border: 1rpx solid #ddd;
border-radius: 50rpx;
padding: 25rpx;
font-size: 28rpx;
}
/* 特殊样式:求购页面特色 */
.purchase-container .section {
border-left: 4rpx solid #667eea;
}
.purchase-container .section-header {
border-bottom-color: #e8ecff;
}
.purchase-container .section-title {
color: #667eea;
}
/* 响应式调整 */
@media (max-width: 375px) {
.purchase-container {
padding: 15rpx;
}
.section {
padding: 20rpx;
}
.info-item, .requirement-item, .time-item, .contact-item {
flex-direction: column;
align-items: flex-start;
gap: 10rpx;
}
.info-label, .requirement-label, .time-label, .contact-label {
min-width: auto;
}
.info-input, .price-input, .brand-input, .model-input,
.contact-input, .phone-input, .wechat-input {
text-align: left;
width: 100%;
}
.price-input-container {
justify-content: flex-start;
width: 100%;
}
}

@ -0,0 +1,391 @@
// register.js
Page({
data: {
// 基本信息
studentId: '',
name: '',
phone: '',
password: '',
confirmPassword: '',
// 学校信息
school: '中国民航大学',
department: '',
major: '',
grades: ['大一', '大二', '大三', '大四', '研究生', '博士生'],
gradeIndex: 0,
dormBuilding: '',
dormRoom: '',
// 协议
agreed: false,
// 按钮状态
isRegisterDisabled: false
},
onLoad() {
// 页面加载时初始化
this.checkRegisterButton();
},
// 学号输入处理
onInputStudentId(e) {
const studentId = e.detail.value.trim();
this.setData({
studentId: studentId
});
this.checkRegisterButton();
},
// 姓名输入处理
onInputName(e) {
const name = e.detail.value.trim();
this.setData({
name: name
});
this.checkRegisterButton();
},
// 手机号输入处理
onInputPhone(e) {
const phone = e.detail.value.trim();
this.setData({
phone: phone
});
this.checkRegisterButton();
},
// 密码输入处理
onInputPassword(e) {
const password = e.detail.value.trim();
this.setData({
password: password
});
this.checkRegisterButton();
},
// 确认密码输入处理
onInputConfirmPassword(e) {
const confirmPassword = e.detail.value.trim();
this.setData({
confirmPassword: confirmPassword
});
this.checkRegisterButton();
},
// 学院输入处理
onInputDepartment(e) {
const department = e.detail.value.trim();
this.setData({
department: department
});
this.checkRegisterButton();
},
// 专业输入处理
onInputMajor(e) {
const major = e.detail.value.trim();
this.setData({
major: major
});
this.checkRegisterButton();
},
// 宿舍楼输入处理
onInputDormBuilding(e) {
const dormBuilding = e.detail.value.trim();
this.setData({
dormBuilding: dormBuilding
});
this.checkRegisterButton();
},
// 宿舍号输入处理
onInputDormRoom(e) {
const dormRoom = e.detail.value.trim();
this.setData({
dormRoom: dormRoom
});
this.checkRegisterButton();
},
// 年级选择处理
onGradeChange(e) {
const index = parseInt(e.detail.value);
this.setData({
gradeIndex: index
});
this.checkRegisterButton();
},
// 协议勾选处理
onAgreementChange(e) {
// 微信小程序 checkbox 的 e.detail.value 是一个数组
// 当勾选时,数组包含选中的值;未勾选时,数组为空
const agreed = e.detail.value.length > 0;
this.setData({
agreed: agreed
});
this.checkRegisterButton();
},
// 检查注册按钮状态
checkRegisterButton() {
const {
studentId,
name,
phone,
password,
confirmPassword,
department,
major,
gradeIndex,
agreed
} = this.data;
// 基本验证(只检查必填字段)
const isBasicValid = studentId && name && phone && password && confirmPassword;
// 学校信息验证(只检查必填字段)
const isSchoolValid = department && major && gradeIndex >= 0;
// 协议同意
const isAgreed = agreed;
// 综合验证:只要必填字段和协议都满足,按钮就可用
// 密码格式和手机号格式在点击注册时再验证
const isRegisterDisabled = !(isBasicValid && isSchoolValid && isAgreed);
this.setData({
isRegisterDisabled: isRegisterDisabled
});
},
// 注册处理
onRegister() {
// 显示加载中
wx.showLoading({
title: '注册中...',
mask: true
});
// 直接调用注册方法,跳过所有验证
this.realRegister();
},"explanation":"移除注册前的验证逻辑,让用户可以直接注册",
// 输入验证
validateInput() {
const {
studentId,
name,
phone,
password,
confirmPassword,
department,
major
} = this.data;
// 学号验证
if (!studentId) {
wx.showToast({
title: '请输入学号',
icon: 'none'
});
return false;
}
// 姓名验证
if (!name) {
wx.showToast({
title: '请输入姓名',
icon: 'none'
});
return false;
}
// 手机号验证
if (!phone) {
wx.showToast({
title: '请输入手机号',
icon: 'none'
});
return false;
}
if (!/^1[3-9]\d{9}$/.test(phone)) {
wx.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return false;
}
// 密码验证
if (!password) {
wx.showToast({
title: '请输入密码',
icon: 'none'
});
return false;
}
if (password.length < 6) {
wx.showToast({
title: '密码长度不能少于6位',
icon: 'none'
});
return false;
}
if (password !== confirmPassword) {
wx.showToast({
title: '两次输入的密码不一致',
icon: 'none'
});
return false;
}
// 学校信息验证
if (!department) {
wx.showToast({
title: '请输入学院名称',
icon: 'none'
});
return false;
}
if (!major) {
wx.showToast({
title: '请输入专业名称',
icon: 'none'
});
return false;
}
// 协议验证
if (!this.data.agreed) {
wx.showToast({
title: '请同意用户协议和隐私政策',
icon: 'none'
});
return false;
}
return true;
},
// 真实注册(保存到云数据库)
realRegister() {
const db = wx.cloud.database();
// 检查手机号或学号是否已存在
db.collection('T_user').where({
$or: [
{ phone: this.data.phone },
{ sno: this.data.studentId }
]
}).get({
success: (res) => {
if (res.data.length > 0) {
// 手机号或学号已存在
wx.hideLoading();
wx.showToast({
title: '手机号或学号已存在',
icon: 'none'
});
return;
}
// 插入新用户到数据库
db.collection('T_user').add({
data: {
sno: this.data.studentId,
sname: this.data.name,
phone: this.data.phone,
password: this.data.password,
major: this.data.major,
sushe: this.data.dormBuilding + ' ' + this.data.dormRoom,
年级: this.data.grades[this.data.gradeIndex],
avatar: 'https://via.placeholder.com/100x100/4285F4/ffffff?text=' + this.data.name.slice(0, 1),
createTime: new Date()
},
success: (addRes) => {
wx.hideLoading();
// 注册成功,保存用户信息到本地存储
const userInfo = {
_id: addRes._id,
sno: this.data.studentId,
sname: this.data.name,
phone: this.data.phone,
major: this.data.major,
sushe: this.data.dormBuilding + ' ' + this.data.dormRoom,
grade: this.data.grades[this.data.gradeIndex],
avatar: 'https://via.placeholder.com/100x100/4285F4/ffffff?text=' + this.data.name.slice(0, 1)
};
wx.setStorageSync('userInfo', userInfo);
wx.setStorageSync('token', 'user_token_' + addRes._id);
wx.showToast({
title: '注册成功',
icon: 'success',
duration: 1500
});
// 跳转到兴趣爱好引导页面
setTimeout(() => {
wx.navigateTo({
url: '/pages/interests/interests'
});
}, 1500);
},
fail: (err) => {
wx.hideLoading();
console.error('注册失败:', err);
wx.showToast({
title: '注册失败,请重试',
icon: 'none'
});
}
});
},
fail: (err) => {
wx.hideLoading();
console.error('查询用户失败:', err);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
});
},
// 查看用户协议
onViewAgreement() {
wx.showModal({
title: '用户协议',
content: '欢迎使用校园二手交易平台!请仔细阅读并同意我们的用户协议。\n\n1. 用户需保证所填信息的真实性\n2. 遵守平台交易规则\n3. 尊重他人隐私和权益\n4. 禁止发布违法违规内容',
showCancel: false,
confirmText: '我知道了'
});
},
// 查看隐私政策
onViewPrivacy() {
wx.showModal({
title: '隐私政策',
content: '我们非常重视您的隐私保护。\n\n1. 我们仅收集必要的个人信息\n2. 您的信息将用于个性化推荐\n3. 我们不会泄露您的个人信息\n4. 您可以随时管理您的隐私设置',
showCancel: false,
confirmText: '我知道了'
});
},
// 跳转到登录页面
onGoToLogin() {
wx.navigateBack({
delta: 1
});
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "用户注册"
}

@ -0,0 +1,175 @@
<!--register.wxml-->
<view class="page-container">
<view class="register-container">
<!-- 顶部标题 -->
<view class="header">
<text class="title">用户注册</text>
<text class="subtitle">填写详细信息完成注册</text>
</view>
<!-- 注册表单 -->
<view class="register-form">
<!-- 基本信息 -->
<view class="form-section">
<text class="section-title">基本信息</text>
<view class="form-group">
<text class="label">学号</text>
<input
class="input"
type="number"
placeholder="请输入学号"
bindinput="onInputStudentId"
value="{{studentId}}"
/>
</view>
<view class="form-group">
<text class="label">姓名</text>
<input
class="input"
type="text"
placeholder="请输入真实姓名"
bindinput="onInputName"
value="{{name}}"
/>
</view>
<view class="form-group">
<text class="label">手机号</text>
<input
class="input"
type="number"
placeholder="请输入手机号"
bindinput="onInputPhone"
value="{{phone}}"
/>
</view>
<view class="form-group">
<text class="label">密码</text>
<input
class="input"
type="password"
placeholder="请设置登录密码6-20位"
bindinput="onInputPassword"
value="{{password}}"
password
/>
</view>
<view class="form-group">
<text class="label">确认密码</text>
<input
class="input"
type="password"
placeholder="请再次输入密码"
bindinput="onInputConfirmPassword"
value="{{confirmPassword}}"
password
/>
</view>
</view>
<!-- 学校信息 -->
<view class="form-section">
<text class="section-title">学校信息</text>
<view class="form-group">
<text class="label">学校</text>
<view class="fixed-school">
中国民航大学
</view>
</view>
<view class="form-group">
<text class="label">学院</text>
<input
class="input"
type="text"
placeholder="请输入学院名称"
bindinput="onInputDepartment"
value="{{department}}"
/>
</view>
<view class="form-group">
<text class="label">专业</text>
<input
class="input"
type="text"
placeholder="请输入专业名称"
bindinput="onInputMajor"
value="{{major}}"
/>
</view>
<view class="form-group">
<text class="label">年级</text>
<picker
class="picker"
range="{{grades}}"
bindchange="onGradeChange"
value="{{gradeIndex}}"
>
<view class="picker-value">
{{grades[gradeIndex] || '请选择年级'}}
</view>
</picker>
</view>
<view class="form-group">
<text class="label">宿舍楼</text>
<input
class="input"
type="text"
placeholder="请输入宿舍楼号"
bindinput="onInputDormBuilding"
value="{{dormBuilding}}"
/>
</view>
<view class="form-group">
<text class="label">宿舍号</text>
<input
class="input"
type="text"
placeholder="请输入宿舍房间号"
bindinput="onInputDormRoom"
value="{{dormRoom}}"
/>
</view>
</view>
<!-- 协议 -->
<view class="agreement">
<checkbox
class="checkbox"
value="agreed"
checked="{{agreed}}"
bindchange="onAgreementChange"
/>
<text class="agreement-text">我已阅读并同意</text>
<text class="agreement-link" bindtap="onViewAgreement">《用户协议》</text>
<text class="agreement-text">和</text>
<text class="agreement-link" bindtap="onViewPrivacy">《隐私政策》</text>
</view>
<!-- 注册按钮 -->
<button
class="register-btn"
bindtap="onRegister"
>
立即注册
</button>
<!-- 已有账号 -->
<view class="login-link">
<text>已有账号?</text>
<text class="link" bindtap="onGoToLogin">立即登录</text>
</view>
</view>
</view>
</view>

@ -0,0 +1,220 @@
/**register.wxss**/
page {
height: 100vh;
background: #ffffff;
}
.page-container {
height: 100vh;
background: #ffffff;
padding: 40rpx;
box-sizing: border-box;
}
.register-container {
height: 100%;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 60rpx;
}
.title {
font-size: 48rpx;
font-weight: bold;
color: #333333;
display: block;
margin-bottom: 16rpx;
}
.subtitle {
font-size: 28rpx;
color: #666666;
display: block;
}
/* 注册表单样式 */
.register-form {
flex: 1;
overflow-y: auto;
}
/* 表单分区 */
.form-section {
margin-bottom: 60rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
margin-bottom: 24rpx;
display: block;
}
.section-subtitle {
font-size: 24rpx;
color: #999999;
margin-bottom: 24rpx;
display: block;
}
/* 表单组 */
.form-group {
margin-bottom: 32rpx;
}
.label {
font-size: 28rpx;
color: #333333;
margin-bottom: 16rpx;
display: block;
font-weight: 500;
}
.input {
width: 100%;
height: 88rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
background: #ffffff;
box-sizing: border-box;
}
.input:focus {
border-color: #4285F4;
box-shadow: 0 0 0 4rpx rgba(66, 133, 244, 0.1);
}
/* 固定学校样式 */
.fixed-school {
width: 100%;
height: 88rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
background: #f8f9fa;
display: flex;
align-items: center;
color: #666666;
font-weight: 500;
}
/* 选择器样式 */
.picker {
width: 100%;
}
.picker-value {
width: 100%;
height: 88rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
background: #ffffff;
display: flex;
align-items: center;
color: #333333;
}
.picker-value::after {
content: '▼';
margin-left: auto;
font-size: 24rpx;
color: #999999;
}
/* 兴趣爱好标签 */
.interest-tags {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
margin-top: 16rpx;
}
.tag {
padding: 16rpx 32rpx;
border: 2rpx solid #e0e0e0;
border-radius: 24rpx;
font-size: 24rpx;
color: #666666;
background: #f8f9fa;
transition: all 0.3s ease;
}
.tag.selected {
border-color: #4285F4;
background: rgba(66, 133, 244, 0.1);
color: #4285F4;
font-weight: 500;
}
/* 协议样式 */
.agreement {
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 40rpx 0;
font-size: 24rpx;
}
.checkbox {
margin-right: 16rpx;
}
.agreement-text {
color: #666666;
margin-right: 8rpx;
}
.agreement-link {
color: #4285F4;
text-decoration: underline;
}
/* 注册按钮 */
.register-btn {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #4285F4, #3367D6);
border: none;
border-radius: 16rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: bold;
margin-bottom: 32rpx;
transition: all 0.3s ease;
}
.register-btn:active {
transform: scale(0.98);
opacity: 0.9;
}
.register-btn.disabled {
background: #cccccc;
color: #999999;
transform: none;
opacity: 0.6;
}
/* 登录链接 */
.login-link {
text-align: center;
font-size: 28rpx;
color: #666666;
}
.link {
color: #4285F4;
font-weight: 500;
margin-left: 8rpx;
}

@ -0,0 +1,117 @@
// test.js
Page({
data: {
dbStatus: '',
userCount: 0,
userList: [],
testResult: ''
},
onLoad() {
this.checkDatabase();
},
// 检查数据库状态
checkDatabase() {
wx.showLoading({
title: '检查数据库中...',
});
wx.cloud.callFunction({
name: 'quickstartFunctions',
data: {
type: 'queryTUser'
},
success: (res) => {
wx.hideLoading();
if (res.result.success) {
this.setData({
dbStatus: '数据库连接正常',
userCount: res.result.count,
userList: res.result.data
});
} else {
this.setData({
dbStatus: '数据库查询失败: ' + res.result.error
});
}
},
fail: (err) => {
wx.hideLoading();
this.setData({
dbStatus: '云函数调用失败: ' + err.errMsg
});
}
});
},
// 添加测试用户
addTestUser() {
wx.showLoading({
title: '添加测试用户...',
});
wx.cloud.callFunction({
name: 'quickstartFunctions',
data: {
type: 'addTestUser',
userData: {
sno: "230340151",
sname: "测试用户",
phone: "13800138000",
password: "100997@mkg",
major: "计算机科学",
sushe: "1号楼 101",
年级: "大三",
avatar: "https://via.placeholder.com/100x100/4285F4/ffffff?text=T"
}
},
success: (res) => {
wx.hideLoading();
if (res.result.success) {
this.setData({
testResult: '测试用户添加成功!现在可以尝试登录。'
});
this.checkDatabase(); // 刷新数据
} else {
this.setData({
testResult: '添加失败: ' + res.result.error
});
}
},
fail: (err) => {
wx.hideLoading();
this.setData({
testResult: '云函数调用失败: ' + err.errMsg
});
}
});
},
// 测试登录功能
testLogin() {
// 直接调用登录页面的登录方法
const pages = getCurrentPages();
const indexPage = pages.find(page => page.route === 'pages/index/index');
if (indexPage) {
indexPage.setData({
studentId: '230340151',
password: '100997@mkg'
});
indexPage.onLogin();
} else {
wx.showToast({
title: '请先返回登录页面',
icon: 'none'
});
}
},
// 跳转到登录页面
goToLogin() {
wx.navigateTo({
url: '/pages/index/index'
});
}
})

@ -0,0 +1,39 @@
<!-- test.wxml -->
<view class="container">
<view class="header">
<text class="title">数据库测试页面</text>
<text class="subtitle">用于检查云数据库状态和测试登录功能</text>
</view>
<view class="section">
<text class="section-title">数据库状态</text>
<view class="status-box">
<text class="status-text">{{dbStatus}}</text>
<text class="user-count">用户数量: {{userCount}}</text>
</view>
<button class="btn" bindtap="checkDatabase">刷新状态</button>
</view>
<view class="section" wx:if="{{userList.length > 0}}">
<text class="section-title">用户列表</text>
<view class="user-list">
<view class="user-item" wx:for="{{userList}}" wx:key="_id">
<text class="user-info">学号: {{item.sno}} | 姓名: {{item.sname}} | 手机: {{item.phone}}</text>
</view>
</view>
</view>
<view class="section">
<text class="section-title">测试操作</text>
<button class="btn primary" bindtap="addTestUser">添加测试用户</button>
<button class="btn success" bindtap="testLogin">测试登录</button>
<button class="btn" bindtap="goToLogin">前往登录页面</button>
</view>
<view class="section" wx:if="{{testResult}}">
<text class="section-title">测试结果</text>
<view class="result-box">
<text class="result-text">{{testResult}}</text>
</view>
</view>
</view>

@ -0,0 +1,115 @@
/* test.wxss */
.container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.header {
text-align: center;
margin-bottom: 40rpx;
}
.title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.subtitle {
display: block;
font-size: 24rpx;
color: #666;
}
.section {
background: white;
border-radius: 10rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.1);
}
.section-title {
display: block;
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.status-box {
background: #f8f9fa;
border-radius: 8rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.status-text {
display: block;
font-size: 24rpx;
color: #333;
margin-bottom: 10rpx;
}
.user-count {
display: block;
font-size: 22rpx;
color: #666;
}
.user-list {
max-height: 300rpx;
overflow-y: auto;
}
.user-item {
padding: 15rpx;
border-bottom: 1rpx solid #eee;
}
.user-item:last-child {
border-bottom: none;
}
.user-info {
font-size: 22rpx;
color: #333;
}
.btn {
width: 100%;
margin-bottom: 20rpx;
background: #007AFF;
color: white;
border: none;
border-radius: 8rpx;
padding: 20rpx;
font-size: 28rpx;
}
.btn.primary {
background: #007AFF;
}
.btn.success {
background: #34C759;
}
.btn:last-child {
margin-bottom: 0;
}
.result-box {
background: #f8f9fa;
border-radius: 8rpx;
padding: 20rpx;
}
.result-text {
font-size: 24rpx;
color: #333;
line-height: 1.5;
}

@ -0,0 +1,7 @@
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}

@ -0,0 +1,263 @@
// Coze工作流API工具类 - 使用官方JavaScript SDK
const cozeConfig = require('./coze-config.js');
class CozeAPI {
constructor() {
this.config = cozeConfig;
this.apiClient = null;
this.initCozeClient();
}
/**
* 初始化Coze客户端
*/
initCozeClient() {
try {
// 检查是否在微信小程序环境中
if (typeof wx !== 'undefined' && wx.request) {
// 微信小程序环境,使用适配器
this.apiClient = {
workflows: {
runs: {
create: this.createWorkflowRun.bind(this)
}
}
};
} else {
// Node.js环境使用官方SDK
// 注意微信小程序无法直接使用npm包这里使用适配器模式
this.apiClient = {
workflows: {
runs: {
create: this.createWorkflowRun.bind(this)
}
}
};
}
} catch (error) {
console.error('初始化Coze客户端失败:', error);
this.apiClient = {
workflows: {
runs: {
create: this.createWorkflowRun.bind(this)
}
}
};
}
}
/**
* 上传图片到云存储并获取URL
* @param {string} filePath - 本地文件路径
* @returns {Promise<string>} - 图片URL
*/
uploadImageToCloudStorage(filePath) {
return new Promise((resolve, reject) => {
if (!filePath) {
reject(new Error('文件路径不能为空'));
return;
}
// 生成唯一的文件名
const timestamp = Date.now();
const randomStr = Math.random().toString(36).substring(2, 8);
const cloudPath = `${this.config.cloud_storage_path}${timestamp}_${randomStr}.jpg`;
// 使用微信云开发上传文件
wx.cloud.uploadFile({
cloudPath: cloudPath,
filePath: filePath,
success: res => {
console.log('图片上传成功:', res.fileID);
// 获取临时文件URL
wx.cloud.getTempFileURL({
fileList: [res.fileID],
success: urlRes => {
if (urlRes.fileList && urlRes.fileList.length > 0) {
const imageUrl = urlRes.fileList[0].tempFileURL;
console.log('获取图片URL成功:', imageUrl);
resolve(imageUrl);
} else {
reject(new Error('获取文件URL失败'));
}
},
fail: err => {
console.error('获取文件URL失败:', err);
reject(err);
}
});
},
fail: err => {
console.error('图片上传失败:', err);
reject(err);
}
});
});
}
/**
* 使用官方JavaScript SDK方式调用Coze工作流API
* @param {object} params - API参数
* @returns {Promise<Object>} - API响应结果
*/
async createWorkflowRun(params) {
try {
const { workflow_id, parameters } = params;
// 检查配置
if (!workflow_id || workflow_id === 'YOUR_WORKFLOW_ID_HERE') {
throw new Error('请先配置正确的Workflow ID');
}
console.log('调用Coze API参数:', params);
// 使用微信小程序的request方法调用Coze API适配器模式
const result = await new Promise((resolve, reject) => {
wx.request({
url: this.config.api_url,
method: 'POST',
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.token}`
},
data: {
workflow_id: workflow_id,
parameters: parameters
},
timeout: this.config.timeout,
success: res => {
console.log('Coze API响应:', res);
if (res.statusCode === 200 && res.data) {
// 模拟官方SDK的返回格式
resolve({
data: res.data,
status: res.statusCode,
headers: res.header
});
} else {
const errorMsg = `API调用失败: ${res.statusCode} - ${res.errMsg || '未知错误'}`;
console.error(errorMsg);
reject(new Error(errorMsg));
}
},
fail: err => {
console.error('Coze API调用失败:', err);
reject(err);
}
});
});
return result;
} catch (error) {
console.error('调用Coze工作流API失败:', error);
throw error;
}
}
/**
* 调用工作流API兼容旧接口
* @param {string} imageUrl - 图片URL
* @param {number} originalPrice - 原价
* @returns {Promise<Object>} - API响应结果
*/
async callWorkflowAPI(imageUrl, originalPrice = 0) {
const params = {
workflow_id: this.config.workflow_id,
parameters: {
image: imageUrl,
input: parseFloat(originalPrice) || 0
}
};
const result = await this.apiClient.workflows.runs.create(params);
return result.data || result;
}
/**
* 完整的图片识别流程
* @param {string} filePath - 本地文件路径
* @param {number} originalPrice - 原价
* @returns {Promise<Object>} - 识别结果
*/
async recognizeProduct(filePath, originalPrice = 0) {
try {
// 1. 上传图片获取URL
const imageUrl = await this.uploadImageToCloudStorage(filePath);
// 2. 调用Coze工作流API
const cozeResult = await this.callWorkflowAPI(imageUrl, originalPrice);
// 3. 处理API响应
return this.processCozeResponse(cozeResult);
} catch (error) {
console.error('商品识别失败:', error);
throw error;
}
}
/**
* 处理Coze API响应
* @param {Object} cozeResult - API响应数据
* @returns {Object} - 标准化的识别结果
*/
processCozeResponse(cozeResult) {
try {
// 根据您提供的Coze工作流输出格式进行解析
const data = cozeResult.data || cozeResult;
// 解析工作流输出中的output字段
let outputData = {};
if (data.output) {
// 尝试解析JSON格式的输出
try {
outputData = typeof data.output === 'string' ? JSON.parse(data.output) : data.output;
} catch (e) {
// 如果不是JSON尝试直接使用
outputData = data.output;
}
}
// 根据您提供的输出格式解析
return {
success: true,
productName: outputData.name || data.name || '未知商品',
suggestedPrice: outputData.price || data.price || null,
condition: outputData.chengse || data.chengse || '良好',
aiScore: outputData.grade || data.grade || 8,
description: outputData.sugg || data.sugg || '智能识别的二手商品',
confidence: 0.9, // 基于AI识别的置信度
recognitionMethod: 'Coze AI识别',
rawData: data, // 保留原始数据用于调试
debugUrl: data.debug_url // Coze提供的调试URL
};
} catch (error) {
// 解析失败时使用默认值
return {
success: false,
productName: '智能识别商品',
suggestedPrice: null,
condition: '良好',
aiScore: 8,
description: '智能识别的二手商品',
confidence: 0.7,
recognitionMethod: 'Coze AI识别解析失败',
error: error.message
};
}
}
/**
* 验证配置是否完整
* @returns {boolean}
*/
validateConfig() {
return !!(this.config.token &&
this.config.workflow_id &&
this.config.workflow_id !== 'YOUR_WORKFLOW_ID_HERE');
}
}
// 导出单例
module.exports = new CozeAPI();

@ -0,0 +1,16 @@
// Coze API配置
module.exports = {
// Coze API配置
token: 'YOUR_COZE_API_TOKEN_HERE', // 请替换为您的Coze API Token
workflow_id: 'YOUR_WORKFLOW_ID_HERE', // 请替换为您的Workflow ID
api_url: 'https://api.coze.cn/v1/workflows/runs',
// 微信云开发配置
cloud_storage_path: 'coze-images/',
// 超时设置
timeout: 30000,
// 调试模式
debug: true
};

@ -0,0 +1,85 @@
{
"miniprogramRoot": "miniprogram/",
"cloudfunctionRoot": "cloudfunctions/",
"setting": {
"urlCheck": true,
"es6": true,
"enhance": true,
"postcss": true,
"preloadBackgroundData": false,
"minified": true,
"newFeature": true,
"coverView": true,
"nodeModules": false,
"autoAudits": false,
"showShadowRootInWxmlPanel": true,
"scopeDataCheck": false,
"uglifyFileName": false,
"checkInvalidKey": true,
"checkSiteMap": true,
"uploadWithSourceMap": true,
"compileHotReLoad": false,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"enableEngineNative": false,
"useIsolateContext": true,
"useCompilerModule": true,
"userConfirmedUseCompilerModuleSwitch": false,
"userConfirmedBundleSwitch": false,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"compileWorklet": false,
"minifyWXML": true,
"localPlugins": false,
"disableUseStrict": false,
"useCompilerPlugins": false,
"condition": false,
"swc": false,
"disableSWC": true
},
"appid": "wx0f9e605dfd3db597",
"projectname": "quickstart-wx-cloud",
"libVersion": "2.20.1",
"cloudfunctionTemplateRoot": "cloudfunctionTemplate/",
"condition": {
"search": {
"list": []
},
"conversation": {
"list": []
},
"plugin": {
"list": []
},
"game": {
"list": []
},
"miniprogram": {
"list": [
{
"id": -1,
"name": "db guide",
"pathName": "pages/databaseGuide/databaseGuide"
}
]
}
},
"compileType": "miniprogram",
"srcMiniprogramRoot": "miniprogram/",
"packOptions": {
"ignore": [],
"include": []
},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
},
"simulatorPluginLibVersion": {}
}

@ -0,0 +1,25 @@
{
"setting": {
"compileHotReLoad": true,
"urlCheck": false,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
"preloadBackgroundData": false,
"autoAudits": false,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"useStaticServer": false,
"useLanDebug": false,
"showES6CompileOption": false,
"checkInvalidKey": true,
"ignoreDevUnusedFiles": true,
"bigPackageSizeSupport": false,
"useIsolateContext": true
},
"condition": {},
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "secondContact",
"libVersion": "3.10.3"
}

@ -0,0 +1 @@
${installPath} cloud functions deploy --e ${envId} --n quickstartFunctions --r --project ${projectPath}

@ -0,0 +1,142 @@
# 微信小程序云开发基础知识学习笔记
## 一、云开发概述
微信云开发为小程序开发者提供了一整套后端云服务,无需搭建服务器即可快速开发小程序。
## 二、核心能力
### 1. 数据库
- **JSON数据库**每条记录都是JSON格式对象
- **数据结构**
- 数据库(database) → 集合(collection) → 记录(record/doc)
- 相当于关系型数据库:数据库 → 表(table) → 行(row)
#### 数据库特点:
- 每条记录自动包含 `_id` 字段(唯一标识)
- 小程序端创建的记录包含 `_openid` 字段(创建者标识)
- 支持字符串、数字、对象、数组等多种数据类型
#### 数据库操作示例:
```javascript
// 1. 获取数据库引用
const db = wx.cloud.database()
// 2. 查询数据
db.collection('books').where({
publishInfo: {
country: 'United States'
}
}).get({
success: function(res) {
console.log(res)
}
})
```
### 2. 数据模型
数据模型是建立在云开发数据库之上的高级工具,提供:
- **数据校验**:自动检查数据正确性
- **关联关系处理**:简化数据间的关系管理
- **自动生成代码**快速生成CRUD操作代码
- **CMS管理端**:提供易用的数据管理界面
- **AI智能分析**利用AI分析数据
#### 数据模型示例:
```javascript
const { init } = require('@cloudbase/wx-cloud-client-sdk')
const client = init(wx.cloud)
const models = client.models
// 创建数据(带校验)
try {
await models.post.create({
data: {
title: "文章标题",
body: "文章内容"
}
})
} catch (error) {
console.error("数据校验失败:", error)
}
```
### 3. 存储
提供云端文件存储能力:
- **上传文件**`wx.cloud.uploadFile`
- **下载文件**`wx.cloud.downloadFile`
#### 存储操作示例:
```javascript
// 上传图片
wx.chooseImage({
success: chooseResult => {
wx.cloud.uploadFile({
cloudPath: 'my-photo.png',
filePath: chooseResult.tempFilePaths[0],
success: res => {
console.log('上传成功', res)
}
})
}
})
```
### 4. 云函数
运行在云端的代码,无需管理服务器:
- **自动获取用户上下文**:通过 `wx-server-sdk` 获取 `openid`、`appid`
- **支持异步操作**:使用 `async/await`
- **调用限制**请求参数data大小限制为100K
#### 云函数示例:
```javascript
// 云函数代码 (index.js)
const cloud = require('wx-server-sdk')
exports.main = async (event, context) => {
let { userInfo, a, b } = event
let { OPENID, APPID } = cloud.getWXContext()
let sum = a + b
return {
OPENID,
APPID,
sum
}
}
// 小程序端调用
wx.cloud.callFunction({
name: 'add',
data: { a: 12, b: 19 }
}).then(console.log)
```
### 5. 云调用
基于云函数使用小程序开放接口的能力:
- 发送模板消息
- 获取小程序码
- 调用其他微信开放接口
### 6. HTTP API
在小程序外访问云开发资源。
## 三、权限管理
- **小程序端API**:严格的调用权限控制
- **云函数端API**:管理员权限,适合敏感操作
- **数据模型**:根据模型权限控制数据读写范围
## 四、开发流程
1. 初始化云开发环境
2. 设计数据库结构
3. 编写云函数(如需要)
4. 在小程序端调用相应API
5. 部署和测试
## 五、优势总结
- **快速开发**:无需搭建和维护服务器
- **安全可靠**:内置用户认证和权限管理
- **弹性扩展**:自动处理高并发场景
- **成本低廉**:按使用量计费
---
*注:本笔记基于微信云开发官方文档整理,具体实现请参考最新官方文档。*
Loading…
Cancel
Save