caolinxuan 1 month ago
parent
commit
d830ee9d92
100 changed files with 3902 additions and 0 deletions
  1. 62 0
      pages/calendar/index.vue
  2. 424 0
      pages/course/detail.vue
  3. 306 0
      pages/discover/index.vue
  4. 96 0
      pages/message/index.vue
  5. 1 0
      pages/message/selected.vue
  6. 169 0
      pages/mine/Merchant.vue
  7. 80 0
      pages/mine/about.vue
  8. 76 0
      pages/mine/cancelAccount.vue
  9. 137 0
      pages/mine/changePhone.vue
  10. 141 0
      pages/mine/feedback.vue
  11. 217 0
      pages/mine/index.vue
  12. 73 0
      pages/mine/notify.vue
  13. 241 0
      pages/mine/profile.vue
  14. 95 0
      pages/mine/recycle.vue
  15. 65 0
      pages/mine/service.vue
  16. 93 0
      pages/mine/setPassword.vue
  17. 108 0
      pages/mine/setting.vue
  18. 82 0
      pages/mine/unbindWechat.vue
  19. 49 0
      pages/search/index.vue
  20. BIN
      static/1.jpg
  21. BIN
      static/2.png
  22. BIN
      static/calender.png
  23. BIN
      static/cuotiben.png
  24. BIN
      static/dingyuedianpu.png
  25. BIN
      static/huishouzhan.png
  26. BIN
      static/kefu.png
  27. BIN
      static/liaojie.png
  28. BIN
      static/msg1.png
  29. BIN
      static/msg2.png
  30. BIN
      static/msg3.png
  31. BIN
      static/msg4.png
  32. BIN
      static/shangjiadianpu.png
  33. BIN
      static/shezhi.png
  34. BIN
      static/supperhuiyuan.png
  35. BIN
      static/tabbar/discover.png
  36. BIN
      static/tabbar/discover_selected.png
  37. BIN
      static/tabbar/home.png
  38. BIN
      static/tabbar/home_selected.png
  39. BIN
      static/tabbar/message.png
  40. BIN
      static/tabbar/message_selected.png
  41. BIN
      static/tabbar/mine.png
  42. BIN
      static/tabbar/mine_selected.png
  43. BIN
      static/tongzhi.png
  44. BIN
      static/xiazai.png
  45. BIN
      static/yijianfankui.png
  46. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/calendar/index.js.map
  47. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/course/detail.js.map
  48. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/discover/index.js.map
  49. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/message/index.js.map
  50. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/message/selected.js.map
  51. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/Merchant.js.map
  52. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/about.js.map
  53. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/cancelAccount.js.map
  54. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/changePhone.js.map
  55. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/feedback.js.map
  56. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/index.js.map
  57. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/notify.js.map
  58. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/profile.js.map
  59. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/recycle.js.map
  60. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/service.js.map
  61. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/setPassword.js.map
  62. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/setting.js.map
  63. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/unbindWechat.js.map
  64. 1 0
      unpackage/dist/dev/.sourcemap/mp-weixin/pages/search/index.js.map
  65. 65 0
      unpackage/dist/dev/mp-weixin/pages/calendar/index.js
  66. 4 0
      unpackage/dist/dev/mp-weixin/pages/calendar/index.json
  67. 1 0
      unpackage/dist/dev/mp-weixin/pages/calendar/index.wxml
  68. 17 0
      unpackage/dist/dev/mp-weixin/pages/calendar/index.wxss
  69. 124 0
      unpackage/dist/dev/mp-weixin/pages/course/detail.js
  70. 4 0
      unpackage/dist/dev/mp-weixin/pages/course/detail.json
  71. 0 0
      unpackage/dist/dev/mp-weixin/pages/course/detail.wxml
  72. 237 0
      unpackage/dist/dev/mp-weixin/pages/course/detail.wxss
  73. 126 0
      unpackage/dist/dev/mp-weixin/pages/discover/index.js
  74. 5 0
      unpackage/dist/dev/mp-weixin/pages/discover/index.json
  75. 1 0
      unpackage/dist/dev/mp-weixin/pages/discover/index.wxml
  76. 173 0
      unpackage/dist/dev/mp-weixin/pages/discover/index.wxss
  77. 37 0
      unpackage/dist/dev/mp-weixin/pages/message/index.js
  78. 5 0
      unpackage/dist/dev/mp-weixin/pages/message/index.json
  79. 1 0
      unpackage/dist/dev/mp-weixin/pages/message/index.wxml
  80. 82 0
      unpackage/dist/dev/mp-weixin/pages/message/index.wxss
  81. 9 0
      unpackage/dist/dev/mp-weixin/pages/message/selected.js
  82. 4 0
      unpackage/dist/dev/mp-weixin/pages/message/selected.json
  83. 1 0
      unpackage/dist/dev/mp-weixin/pages/message/selected.wxml
  84. 1 0
      unpackage/dist/dev/mp-weixin/pages/message/selected.wxss
  85. 55 0
      unpackage/dist/dev/mp-weixin/pages/mine/Merchant.js
  86. 4 0
      unpackage/dist/dev/mp-weixin/pages/mine/Merchant.json
  87. 1 0
      unpackage/dist/dev/mp-weixin/pages/mine/Merchant.wxml
  88. 89 0
      unpackage/dist/dev/mp-weixin/pages/mine/Merchant.wxss
  89. 21 0
      unpackage/dist/dev/mp-weixin/pages/mine/about.js
  90. 4 0
      unpackage/dist/dev/mp-weixin/pages/mine/about.json
  91. 1 0
      unpackage/dist/dev/mp-weixin/pages/mine/about.wxml
  92. 76 0
      unpackage/dist/dev/mp-weixin/pages/mine/about.wxss
  93. 40 0
      unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.js
  94. 4 0
      unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.json
  95. 1 0
      unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.wxml
  96. 34 0
      unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.wxss
  97. 78 0
      unpackage/dist/dev/mp-weixin/pages/mine/changePhone.js
  98. 4 0
      unpackage/dist/dev/mp-weixin/pages/mine/changePhone.json
  99. 1 0
      unpackage/dist/dev/mp-weixin/pages/mine/changePhone.wxml
  100. 58 0
      unpackage/dist/dev/mp-weixin/pages/mine/changePhone.wxss

+ 62 - 0
pages/calendar/index.vue

@@ -0,0 +1,62 @@
+<template>
+  <view class="calendar-page">
+    <view class="calendar-header">
+      <text class="calendar-title">课程日历</text>
+    </view>
+    <view class="calendar-content">
+      <view class="calendar-row calendar-week">
+        <text v-for="w in weeks" :key="w">{{ w }}</text>
+      </view>
+      <view v-for="(row, i) in calendarRows" :key="i" class="calendar-row">
+        <text v-for="d in row" :key="d" :class="{'today': isToday(d)}">{{ d > 0 ? d : '' }}</text>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      weeks: ['日','一','二','三','四','五','六'],
+      calendarRows: this.getCalendarRows()
+    }
+  },
+  methods: {
+    getCalendarRows() {
+      const d = new Date()
+      const year = d.getFullYear()
+      const month = d.getMonth()
+      const firstDay = new Date(year, month, 1).getDay()
+      const days = new Date(year, month + 1, 0).getDate()
+      const rows = []
+      let row = new Array(7).fill(0)
+      let day = 1
+      for (let i = 0; i < 6; i++) {
+        for (let j = 0; j < 7; j++) {
+          if (i === 0 && j < firstDay) continue
+          if (day > days) break
+          row[j] = day++
+        }
+        rows.push([...row])
+        row = new Array(7).fill(0)
+        if (day > days) break
+      }
+      return rows
+    },
+    isToday(d) {
+      const now = new Date()
+      return d === now.getDate()
+    }
+  }
+}
+</script>
+<style scoped>
+.calendar-page { padding: 40rpx; }
+.calendar-header { text-align: center; margin-bottom: 32rpx; }
+.calendar-title { font-size: 36rpx; font-weight: bold; color: #3498db; }
+.calendar-content { background: #fff; border-radius: 16rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04); padding: 24rpx; }
+.calendar-row { display: flex; justify-content: space-between; margin-bottom: 8rpx; }
+.calendar-week text { color: #888; font-size: 28rpx; flex: 1; text-align: center; }
+.calendar-row text { flex: 1; text-align: center; font-size: 30rpx; color: #222; padding: 8rpx 0; border-radius: 8rpx; }
+.today { background: #3498db; color: #fff; }
+</style> 

+ 424 - 0
pages/course/detail.vue

@@ -0,0 +1,424 @@
+<template>
+  <view class="course-detail-container">
+    <!-- 顶部轮播图 -->
+    <swiper class="swiper" circular :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
+      <swiper-item v-for="(image, index) in parsedImages" :key="index">
+        <image :src="image.imageUrl" class="swiper-image" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 商品信息 -->
+    <view class="header">
+      <view class="title">{{ course.name }}</view>
+      <view class="subtitle">{{ course.subtitle }}</view>
+      <view class="price-row">
+        <text class="price">¥{{ course.price?.toFixed(2) }}</text>
+        <text class="original-price">¥{{ course.originalPrice?.toFixed(2) }}</text>
+      </view>
+      <view class="stock">库存: {{ course.stock }}</view>
+    </view>
+
+    <!-- 评价区 -->
+    <view class="section">
+      <view class="section-title">评价 ({{ comments.length }})</view>
+      <view v-if="comments.length === 0" class="empty-comment">暂无评价</view>
+      <view v-else class="comment-list">
+        <view class="comment-item" v-for="item in comments" :key="item.id">
+          <image :src="item.avatar || defaultAvatar" class="comment-avatar" />
+          <view class="comment-main">
+            <view class="comment-user">{{ item.user }}</view>
+            <view class="comment-stars">
+              <text v-for="n in 5" :key="n" class="star" :class="{active: n <= item.star}">★</text>
+            </view>
+            <view class="comment-content">{{ item.content || '此用户没有填写评价' }}</view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- tab切换 -->
+    <view class="tabs">
+      <view :class="['tab', tabIndex===0?'active':'']" @click="tabIndex=0">详情</view>
+      <view :class="['tab', tabIndex===1?'active':'']" @click="tabIndex=1">目录</view>
+      <view :class="['tab', tabIndex===2?'active':'']" @click="tabIndex=2">课堂互动</view>
+    </view>
+
+    <view v-if="tabIndex===0" class="tab-content">
+      <view class="detail-section">
+        <view class="section-title">课程介绍</view>
+        <view class="detail-content">
+          <view v-for="(image, index) in parsedImages" :key="index" class="detail-item">
+            <image :src="image.imageUrl" class="detail-image" mode="widthFix" />
+            <view class="detail-info">
+              <view class="detail-title">{{ image.courseTitle }}</view>
+              <view class="detail-desc">{{ image.courseDesc }}</view>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <view v-else-if="tabIndex===1" class="tab-content">
+      <view v-for="item in catalog" :key="item.id" class="catalog-item">
+        <image :src="item.icon || lockIcon" class="catalog-icon" />
+        <view class="catalog-main">
+          <view class="catalog-title">{{ item.title }}</view>
+          <view class="catalog-meta">{{ item.type }} {{ item.date }} | {{ item.count }}次学习</view>
+        </view>
+        <view v-if="item.trial" class="trial">试学</view>
+      </view>
+    </view>
+
+    <view v-else class="tab-content">
+      <view class="empty-interact">
+        <image src="/static/empty-box.png" class="empty-img" />
+        <view class="empty-tip">该课程暂无互动内容</view>
+      </view>
+    </view>
+
+    <!-- 底部按钮 -->
+    <view class="footer">
+      <button class="service-btn">客服</button>
+      <button class="order-btn">立即购买</button>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      course: {},
+      comments: [],
+      catalog: [],
+      tabIndex: 0,
+      defaultCover: '/static/default-course.png',
+      defaultAvatar: '/static/1.jpg',
+      lockIcon: '/static/lock.png'
+    }
+  },
+  computed: {
+    parsedImages() {
+      try {
+        if (this.course.images) {
+          return JSON.parse(this.course.images)
+        }
+        return []
+      } catch (e) {
+        console.error('解析图片数据失败:', e)
+        return []
+      }
+    }
+  },
+  onLoad(options) {
+    this.fetchDetail(options.id)
+  },
+  methods: {
+    async fetchDetail(id) {
+      try {
+        const res = await uni.request({
+          url: `http://localhost:9527/product/findOne?productId=${id}`,
+          method: 'GET'
+        })
+        
+        if (res.statusCode === 200) {
+          this.course = res.data.data
+          this.comments = res.data.data.comments || []
+          this.catalog = res.data.data.catalog || []
+        } else {
+          throw new Error(res.data.message || '获取数据失败')
+        }
+      } catch (err) {
+        uni.showToast({ 
+          title: err.message || '加载失败', 
+          icon: 'none' 
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.course-detail-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+
+.swiper {
+  width: 100%;
+  height: 500rpx;
+}
+
+.swiper-image {
+  width: 100%;
+  height: 100%;
+}
+
+.header {
+  background: #fff;
+  padding: 24rpx;
+  margin-bottom: 20rpx;
+}
+
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 12rpx;
+}
+
+.subtitle {
+  font-size: 28rpx;
+  color: #666;
+  margin-bottom: 16rpx;
+}
+
+.price-row {
+  display: flex;
+  align-items: baseline;
+  margin-bottom: 12rpx;
+}
+
+.price {
+  color: #ff6600;
+  font-size: 40rpx;
+  font-weight: bold;
+  margin-right: 16rpx;
+}
+
+.original-price {
+  color: #999;
+  font-size: 28rpx;
+  text-decoration: line-through;
+}
+
+.stock {
+  font-size: 26rpx;
+  color: #666;
+}
+
+.section {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 24rpx 24rpx 0 24rpx;
+  padding: 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+}
+
+.section-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  margin-bottom: 16rpx;
+}
+
+.empty-comment {
+  color: #bbb;
+  text-align: center;
+  font-size: 26rpx;
+}
+
+.comment-list {
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+}
+
+.comment-item {
+  display: flex;
+  align-items: flex-start;
+}
+
+.comment-avatar {
+  width: 56rpx;
+  height: 56rpx;
+  border-radius: 50%;
+  margin-right: 16rpx;
+}
+
+.comment-main {
+  flex: 1;
+}
+
+.comment-user {
+  font-size: 26rpx;
+  color: #333;
+  font-weight: 600;
+}
+
+.comment-stars {
+  color: #ffb400;
+  font-size: 24rpx;
+  margin: 4rpx 0 8rpx 0;
+}
+
+.star.active {
+  color: #ffb400;
+}
+
+.star {
+  color: #eee;
+}
+
+.comment-content {
+  font-size: 24rpx;
+  color: #666;
+}
+
+.tabs {
+  display: flex;
+  background: #fff;
+  padding: 0 24rpx;
+  border-bottom: 1rpx solid #eee;
+}
+
+.tab {
+  flex: 1;
+  text-align: center;
+  padding: 24rpx 0;
+  font-size: 30rpx;
+  color: #666;
+  position: relative;
+}
+
+.tab.active {
+  color: #ff6600;
+  font-weight: bold;
+}
+
+.tab.active::after {
+  content: '';
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  transform: translateX(-50%);
+  width: 40rpx;
+  height: 6rpx;
+  background: #ff6600;
+  border-radius: 3rpx;
+}
+
+.tab-content {
+  background: #fff;
+  padding: 24rpx;
+}
+
+.detail-section {
+  margin-bottom: 24rpx;
+}
+
+.detail-item {
+  margin-bottom: 30rpx;
+}
+
+.detail-image {
+  width: 100%;
+  border-radius: 12rpx;
+  margin-bottom: 16rpx;
+}
+
+.detail-info {
+  padding: 0 12rpx;
+}
+
+.detail-title {
+  font-size: 30rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+}
+
+.detail-desc {
+  font-size: 26rpx;
+  color: #666;
+  line-height: 1.6;
+}
+
+.catalog-item {
+  display: flex;
+  align-items: center;
+  padding: 18rpx 0;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+
+.catalog-icon {
+  width: 36rpx;
+  height: 36rpx;
+  margin-right: 16rpx;
+}
+
+.catalog-main {
+  flex: 1;
+}
+
+.catalog-title {
+  font-size: 26rpx;
+  color: #222;
+  font-weight: 600;
+}
+
+.catalog-meta {
+  font-size: 22rpx;
+  color: #888;
+  margin-top: 4rpx;
+}
+
+.trial {
+  color: #ff6600;
+  font-size: 22rpx;
+  border: 1rpx solid #ff6600;
+  border-radius: 8rpx;
+  padding: 2rpx 12rpx;
+  margin-left: 8rpx;
+}
+
+.empty-interact {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: 200rpx;
+}
+
+.empty-img {
+  width: 120rpx;
+  height: 120rpx;
+  margin-bottom: 16rpx;
+  opacity: 0.7;
+}
+
+.empty-tip {
+  color: #bbb;
+  font-size: 26rpx;
+}
+
+.footer {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  display: flex;
+  padding: 16rpx 24rpx;
+  background: #fff;
+  box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05);
+}
+
+.service-btn, .order-btn {
+  flex: 1;
+  height: 80rpx;
+  line-height: 80rpx;
+  text-align: center;
+  border-radius: 40rpx;
+  font-size: 28rpx;
+}
+
+.service-btn {
+  background: #f5f5f5;
+  color: #666;
+  margin-right: 20rpx;
+}
+
+.order-btn {
+  background: #ff6600;
+  color: #fff;
+}
+</style> 

+ 306 - 0
pages/discover/index.vue

@@ -0,0 +1,306 @@
+<template>
+  <view class="container">
+    <view class="spacer"></view>
+    <view class="search-bar">
+      <input v-model="searchText" @confirm="onSearch" placeholder="搜索课程" />
+      <text class="iconfont icon-search"></text>
+    </view>
+    <view class="category-tabs">
+      <view
+        v-for="(tab, idx) in categories"
+        :key="tab.id"
+        :class="['tab', idx === activeTab ? 'active' : '']"
+        @click="activeTab = idx"
+      >{{ tab.name }}</view>
+    </view>
+    
+    <!-- Loading state -->
+    <view v-if="loading" class="loading-container">
+      <uni-load-more status="loading" />
+    </view>
+    
+    <!-- Error state -->
+ <!--   <view v-else-if="error" class="error-container">
+      <text class="error-text">{{ error }}</text>
+      <button class="retry-btn" @click="findAll">重试</button>
+    </view> -->
+    
+    <!-- Content -->
+    <view v-else class="course-grid">
+      <view v-for="cour in courses" :key="cour.id" class="card" @click="navigateToDetail(cour.id)">
+        <image :src="cour.mainImage" class="cover" mode="aspectFill" style="width: 200px;height: 200px;"/>
+        <view class="content">
+          <view class="title">{{ cour.name }}</view>
+          <view class="desc">{{ cour.description }}</view>
+          <view class="price-row">
+            <text class="price">¥{{ cour.price?.toFixed(2) || '0.00' }}</text>
+            <text class="sales">已售 {{ cour.sales || 0 }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      searchText: '',
+      activeTab: 0,
+      categories: [],
+      courses: [],
+      loading: false,
+      error: null,
+      defaultCover: '/static/default-course.png'
+    }
+  },
+  computed: {
+    filteredCourses() {
+      let list = this.courses
+      if (this.activeTab !== 0) {
+        list = list.filter(c => c.category === this.categories[this.activeTab])
+      }
+      if (this.searchText) {
+        list = list.filter(c => 
+          c.title.toLowerCase().includes(this.searchText.toLowerCase()) ||
+          c.description.toLowerCase().includes(this.searchText.toLowerCase())
+        )
+      }
+	  console.log(list)
+      return list
+    }
+  },
+  onLoad() {
+    this.findAll();
+	this.findCategory();
+  },
+  methods: {
+    onSearch() {
+      // Search is handled by computed property
+    },
+	async findCategory() {
+	  this.loading = true
+	  this.error = null
+	  try {
+	    const res = await uni.request({
+	      url: 'http://localhost:9527/product/findCategory',
+	      method: 'GET'
+	    })
+	    console.log(res.data)
+	    if (res.statusCode === 200 ) {
+	      this.categories = res.data.data
+	    } else {
+	      throw new Error(res.data.message || '获取数据失败')
+	    }
+	  } catch (err) {
+	    this.error = err.message || '网络错误,请稍后重试'
+	    console.error('获取课程列表失败:', err)
+	  } finally {
+	    this.loading = false
+	  }
+	},
+    async findAll() {
+      this.loading = true
+      this.error = null
+      try {
+        const res = await uni.request({
+          url: 'http://localhost:9527/product/findAll',
+          method: 'GET'
+        })
+        
+        if (res.statusCode === 200 ) {
+			console.log(res.data.data)
+          this.courses = res.data.data
+        } else {
+          throw new Error(res.data.message || '获取数据失败')
+        }
+      } catch (err) {
+        this.error = err.message || '网络错误,请稍后重试'
+        console.error('获取课程列表失败:', err)
+      } finally {
+        this.loading = false
+      }
+    },
+    navigateToDetail(id) {
+		console.log(id)
+      uni.navigateTo({
+        url: `/pages/course/detail?id=${id}`
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.container { 
+  min-height: 100vh; 
+  background: linear-gradient(180deg,#eaf6ff 0%,#f7f8fa 100%); 
+  padding-bottom: 120rpx; 
+}
+
+.spacer {
+  height: 60rpx;
+  padding-top: 40px;
+}
+
+.search-bar { 
+
+  display: flex; 
+  align-items: center; 
+  background: #fff; 
+  border-radius: 40rpx; 
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); 
+  padding: 0 32rpx; 
+  margin: 0 auto 24rpx auto; 
+  width: 80vw; 
+  max-width: 600rpx; 
+  height: 80rpx; 
+}
+
+input { 
+  flex: 1; 
+  border: none; 
+  background: transparent; 
+  font-size: 30rpx; 
+  height: 80rpx; 
+}
+
+.iconfont { 
+  color: #bbb; 
+  font-size: 36rpx; 
+  margin-left: 10rpx; 
+}
+
+.category-tabs { 
+  display: flex; 
+  margin: 20rpx 0 0 0; 
+  background: #fff; 
+  border-radius: 20rpx; 
+  overflow-x: auto; 
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03); 
+}
+
+.tab { 
+  flex: 1; 
+  text-align: center; 
+  padding: 20rpx 0; 
+  font-size: 30rpx; 
+  color: #666; 
+  position: relative; 
+  white-space: nowrap;
+}
+
+.tab.active { 
+  color: #3498db; 
+  font-weight: bold; 
+}
+
+.tab.active::after { 
+  content: ''; 
+  position: absolute; 
+  left: 50%; 
+  bottom: 0; 
+  transform: translateX(-50%); 
+  width: 40rpx; 
+  height: 6rpx; 
+  background: #3498db; 
+  border-radius: 3rpx; 
+}
+
+.course-grid { 
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 32rpx;
+  padding: 32rpx 24rpx 0 24rpx;
+}
+
+.card { 
+  background: #fff; 
+  border-radius: 20rpx; 
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08); 
+  overflow: hidden;
+  transition: transform 0.2s;
+  display: flex;
+  flex-direction: column;
+  min-height: 380rpx;
+  
+  &:active {
+    transform: scale(0.98);
+  }
+}
+
+.cover { 
+  width: 100%; 
+  height: 140rpx; 
+  background-color: #f5f5f5;
+  border-radius: 20rpx 20rpx 0 0;
+}
+
+.content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  padding: 20rpx 16rpx 16rpx 16rpx;
+}
+
+.title { 
+  font-size: 28rpx; 
+  font-weight: 600; 
+  margin-bottom: 8rpx;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.desc { 
+  font-size: 24rpx; 
+  color: #888; 
+  margin-bottom: 12rpx;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+
+.price-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.price { 
+  color: #e74c3c; 
+  font-size: 28rpx;
+  font-weight: bold;
+}
+
+.sales {
+  font-size: 24rpx;
+  color: #999;
+}
+
+.loading-container,
+.error-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 40rpx;
+}
+
+.error-text {
+  color: #e74c3c;
+  font-size: 28rpx;
+  margin-bottom: 20rpx;
+}
+
+.retry-btn {
+  background: #3498db;
+  color: #fff;
+  padding: 16rpx 32rpx;
+  border-radius: 30rpx;
+  font-size: 28rpx;
+}
+</style> 

+ 96 - 0
pages/message/index.vue

@@ -0,0 +1,96 @@
+<template>
+  <view class="msg-container">
+    <view class="msg-header">消息</view>
+    <view class="msg-list">
+      <view class="msg-item" v-for="item in msgList" :key="item.title" @click="goTo(item)">
+        <view class="msg-icon" :style="{background: item.bg}">
+          <image :src="item.icon" class="icon-img" />
+        </view>
+        <view class="msg-info">
+          <view class="msg-title">{{ item.title }}</view>
+          <view class="msg-desc">暂无新消息</view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      msgList: [
+        { title: '课程精选', icon: '/static/msg1.png', bg: 'linear-gradient(135deg,#ffbcbc,#ffeded)', path: '/pages/message/selected' },
+        { title: '课程上新', icon: '/static/msg2.png', bg: 'linear-gradient(135deg,#b6e3ff,#eaf7ff)', path: '' },
+        { title: '直播预约', icon: '/static/msg3.png', bg: 'linear-gradient(135deg,#d6caff,#f3f0ff)', path: '' },
+        { title: '圈子消息', icon: '/static/msg4.png', bg: 'linear-gradient(135deg,#b6ffe0,#eafff6)', path: '' },
+      ]
+    }
+  },
+  methods: {
+    goTo(item) {
+      if (item.path) {
+        uni.navigateTo({ url: item.path })
+      }
+    }
+  }
+}
+</script>
+<style lang="scss">
+.msg-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.msg-header {
+  text-align: center;
+  font-size: 40rpx;
+  font-weight: bold;
+  color: #222;
+  margin-top: 80rpx;
+  margin-bottom: 40rpx;
+  letter-spacing: 2rpx;
+}
+.msg-list {
+  margin: 0 0 0 0;
+}
+.msg-item {
+  display: flex;
+  align-items: center;
+  padding: 32rpx 40rpx 32rpx 40rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx 32rpx 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  transition: box-shadow 0.2s;
+}
+.msg-item:active {
+  box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.08);
+}
+.msg-icon {
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 32rpx;
+}
+.icon-img {
+  width: 48rpx;
+  height: 48rpx;
+}
+.msg-info {
+  display: flex;
+  flex-direction: column;
+}
+.msg-title {
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #222;
+  margin-bottom: 8rpx;
+}
+.msg-desc {
+  font-size: 24rpx;
+  color: #bbb;
+}
+</style> 

+ 1 - 0
pages/message/selected.vue

@@ -0,0 +1 @@
+<template><view class="simple-page">这里是课程精选详情</view></template><style>.simple-page{padding:100rpx;text-align:center;color:#888;font-size:32rpx;}</style> 

+ 169 - 0
pages/mine/Merchant.vue

@@ -0,0 +1,169 @@
+<template>
+	<view class="main-content">
+		<view class="title">请选择您的知识店铺</view>
+		<view v-if="hasShop" class="shop-card">
+			<view class="shop-info" @click="jump()">
+				<image class="shop-icon" src="/static/shop.png" />
+				<view class="shop-name">知识店铺_WVV350567 <text class="shop-tag">试用版</text></view>
+				<view class="shop-status">最近访问</view>
+			</view>
+			<view class="shop-detail">
+				<view>试用期至:2025-05-10(已过期)</view>
+				<view>访问身份:创建者</view>
+			</view>
+		</view>
+		<view v-else class="no-shop">
+			<image class="no-shop-img" src="/static/no_shop.png" />
+			<view class="no-shop-text">暂无知识店铺,请创建</view>
+		</view>
+		<button class="create-btn" @click="goToShopHome">创建知识店铺</button>
+		<view class="kefu-btn" @click="onKefu">
+			<image class="kefu-img" src="/static/kefu.png" />
+			<text>开店咨询</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				hasShop: true // 模拟有无店铺
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+			jump(){
+				console.log("123123")
+				wx.navigateToMiniProgram({
+						  appId: 'wx3d250e9c83ec74ee', // 必填,未发布小程序的AppID(开发版/体验版均可)
+						  path: 'pages/index/index', // 选填,如:'pages/index/index'
+						  envVersion: 'develop', // 选填,指定跳转环境:develop(开发版)、trial(体验版)、release(正式版),未发布时用'develop'
+						  success(res) {
+						    // 跳转成功回调
+						  },
+						  fail(res) {
+						    // 跳转失败回调(常见原因:AppID错误、未关联、环境不正确)
+						  }
+				});
+			},
+			goToShopHome() {
+				// 跳转到店铺首页
+				uni.switchTab({
+					url: '/pages/index/shopHome',
+					
+				})
+			},
+			onKefu() {
+				uni.showToast({ title: '客服功能待接入', icon: 'none' })
+			}
+		}
+	}
+</script>
+
+<style>
+	.main-content {
+		padding: 40rpx 30rpx 120rpx 30rpx;
+	}
+
+	.title {
+		font-size: 44rpx;
+		font-weight: bold;
+		margin-bottom: 40rpx;
+	}
+
+	.shop-card {
+		background: #f8fafd;
+		border-radius: 20rpx;
+		padding: 36rpx 30rpx;
+		margin-bottom: 40rpx;
+		box-shadow: 0 2rpx 8rpx #f0f1f2;
+	}
+
+	.shop-info {
+		display: flex;
+		align-items: center;
+		margin-bottom: 16rpx;
+	}
+
+	.shop-icon {
+		width: 60rpx;
+		height: 60rpx;
+		margin-right: 20rpx;
+	}
+
+	.shop-name {
+		font-size: 32rpx;
+		font-weight: 500;
+		margin-right: 16rpx;
+	}
+
+	.shop-tag {
+		font-size: 22rpx;
+		color: #fff;
+		background: #b3c6ff;
+		border-radius: 8rpx;
+		padding: 2rpx 10rpx;
+		margin-left: 8rpx;
+	}
+
+	.shop-status {
+		margin-left: auto;
+		color: #b3b3b3;
+		font-size: 26rpx;
+	}
+
+	.shop-detail {
+		color: #888;
+		font-size: 26rpx;
+	}
+
+	.no-shop {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		margin-bottom: 40rpx;
+	}
+
+	.no-shop-img {
+		width: 180rpx;
+		height: 180rpx;
+		margin-bottom: 20rpx;
+	}
+
+	.no-shop-text {
+		color: #b3b3b3;
+		font-size: 30rpx;
+	}
+
+	.create-btn {
+		width: 90%;
+		margin: 0 auto 40rpx auto;
+		background: #1880ff;
+		color: #fff;
+		font-size: 36rpx;
+		border-radius: 50rpx;
+		height: 90rpx;
+		line-height: 90rpx;
+	}
+
+	.kefu-btn {
+		position: fixed;
+		right: 40rpx;
+		bottom: 180rpx;
+		display: flex;
+		align-items: center;
+		background: #eaf3ff;
+		border-radius: 50rpx;
+		padding: 10rpx 30rpx;
+		box-shadow: 0 2rpx 8rpx #eaf3ff;
+	}
+
+	.kefu-img {
+		width: 60rpx;
+		height: 60rpx;
+		margin-right: 10rpx;
+	}
+</style>

+ 80 - 0
pages/mine/about.vue

@@ -0,0 +1,80 @@
+<template>
+  <view class="about-container">
+    <view class="about-title">了解小鹅通</view>
+    <view class="about-box">
+      <image src="/static/logo.png" class="about-logo" />
+      <view class="about-desc">小鹅通,专注知识付费与内容变现,助力每一位内容创作者。</view>
+      <view class="feature-list">
+        <view class="feature-item">· 课程直播与录播</view>
+        <view class="feature-item">· 社群互动</view>
+        <view class="feature-item">· 多端分发</view>
+        <view class="feature-item">· 数据分析</view>
+      </view>
+      <button class="web-btn" @click="goWeb">访问官网</button>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  methods: {
+    goWeb() {
+      uni.setClipboardData({ data: 'https://www.xiaoe-tech.com', success:()=>{
+        uni.showToast({ title: '官网地址已复制', icon: 'none' })
+      } })
+    }
+  }
+}
+</script>
+<style lang="scss">
+.about-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.about-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.about-box {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 48rpx 24rpx 48rpx 24rpx;
+}
+.about-logo {
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 20rpx;
+  margin-bottom: 24rpx;
+}
+.about-desc {
+  font-size: 28rpx;
+  color: #555;
+  margin-bottom: 32rpx;
+  text-align: center;
+}
+.feature-list {
+  width: 100%;
+  margin-bottom: 32rpx;
+}
+.feature-item {
+  font-size: 26rpx;
+  color: #409EFF;
+  margin-bottom: 8rpx;
+  text-align: left;
+}
+.web-btn {
+  width: 80%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+}
+</style> 

+ 76 - 0
pages/mine/cancelAccount.vue

@@ -0,0 +1,76 @@
+<template>
+  <view class="cancel-account-container">
+    <view class="header">账号注销</view>
+    <view class="desc">注销账号将清空所有个人数据且无法恢复,是否确认注销?</view>
+    <button class="submit-btn" type="warn" @click="submit">确认注销</button>
+  </view>
+</template>
+
+<script>
+export default {
+  methods: {
+    submit() {
+      uni.showModal({
+        title: '确认注销',
+        content: '注销后所有数据将无法恢复,是否继续?',
+        success: (res) => {
+          if (res.confirm) {
+            uni.request({
+              url: 'http://localhost:9527/api/cancelAccount',
+              method: 'POST',
+              data: { uid: uni.getStorageSync('uid') },
+              success: (res) => {
+                if (res.statusCode === 200 && res.data.code === 200) {
+                  uni.showToast({ title: '注销成功', icon: 'success' })
+                  setTimeout(() => {
+                    uni.clearStorageSync()
+                    uni.reLaunch({ url: '/pages/index/index' })
+                  }, 1000)
+                } else {
+                  uni.showToast({ title: res.data.message || '注销失败', icon: 'none' })
+                }
+              }
+            })
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.cancel-account-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.header {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+  width: 100%;
+}
+.desc {
+  font-size: 28rpx;
+  color: #e74c3c;
+  margin: 60rpx 0 40rpx 0;
+  text-align: center;
+  padding: 0 32rpx;
+}
+.submit-btn {
+  width: 80%;
+  background: #e74c3c;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}
+</style> 

+ 137 - 0
pages/mine/changePhone.vue

@@ -0,0 +1,137 @@
+<template>
+  <view class="change-phone-container">
+    <view class="header">更换手机号</view>
+    <view class="form">
+      <input v-model="newPhone" type="number" maxlength="11" placeholder="请输入新手机号" class="input" />
+      <view class="code-row">
+        <input v-model="code" maxlength="6" placeholder="请输入验证码" class="input code-input" />
+        <button class="code-btn" :disabled="countdown>0" @click="sendCode">{{ countdown>0 ? countdown+'s' : '获取验证码' }}</button>
+      </view>
+      <button class="submit-btn" @click="submit">确认更换</button>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      newPhone: '',
+      code: '',
+      countdown: 0,
+      timer: null
+    }
+  },
+  methods: {
+    sendCode() {
+      if (!/^1[3-9]\d{9}$/.test(this.newPhone)) {
+        uni.showToast({ title: '请输入正确手机号', icon: 'none' })
+        return
+      }
+      // 调用后端发送验证码接口
+      uni.request({
+        url: 'http://localhost:9527/api/sendCode',
+        method: 'POST',
+        data: { phone: this.newPhone }
+      })
+      uni.showToast({ title: '验证码已发送', icon: 'success' })
+      this.countdown = 60
+      this.timer = setInterval(() => {
+        this.countdown--
+        if (this.countdown <= 0) clearInterval(this.timer)
+      }, 1000)
+    },
+    submit() {
+      if (!/^1[3-9]\d{9}$/.test(this.newPhone)) {
+        uni.showToast({ title: '请输入正确手机号', icon: 'none' })
+        return
+      }
+      if (!/^\d{6}$/.test(this.code)) {
+        uni.showToast({ title: '请输入6位验证码', icon: 'none' })
+        return
+      }
+      // 调用后端更换手机号接口
+      uni.request({
+        url: 'http://localhost:9527/api/updatePhone',
+        method: 'POST',
+        data: {
+          uid: uni.getStorageSync('uid'),
+          phone: this.newPhone,
+          code: this.code
+        },
+        success: (res) => {
+          if (res.statusCode === 200 && res.data.code === 200) {
+            uni.showToast({ title: '更换成功', icon: 'success' })
+            setTimeout(() => uni.navigateBack(), 1000)
+          } else {
+            uni.showToast({ title: res.data.message || '更换失败', icon: 'none' })
+          }
+        }
+      })
+    }
+  },
+  onUnload() {
+    if (this.timer) clearInterval(this.timer)
+  }
+}
+</script>
+
+<style scoped>
+.change-phone-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+}
+.header {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+}
+.form {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 32rpx;
+  padding: 40rpx 32rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  display: flex;
+  flex-direction: column;
+  gap: 32rpx;
+}
+.input {
+  width: 100%;
+  height: 80rpx;
+  border: 1rpx solid #eee;
+  border-radius: 12rpx;
+  padding: 0 24rpx;
+  font-size: 30rpx;
+  background: #f7f8fa;
+}
+.code-row {
+  display: flex;
+  gap: 16rpx;
+}
+.code-input {
+  flex: 1;
+}
+.code-btn {
+  width: 180rpx;
+  height: 80rpx;
+  background: #409EFF;
+  color: #fff;
+  border: none;
+  border-radius: 12rpx;
+  font-size: 28rpx;
+}
+.submit-btn {
+  width: 100%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}
+</style> 

+ 141 - 0
pages/mine/feedback.vue

@@ -0,0 +1,141 @@
+<template>
+  <view class="feedback-container">
+    <view class="feedback-title">意见反馈</view>
+    <view class="feedback-form">
+      <view class="form-row">
+        <image src="/static/logo.png" class="form-icon" />
+        <input class="form-input" v-model="content" placeholder="请输入您的宝贵意见..." />
+      </view>
+      <view class="form-row">
+        <picker :range="typeList" :value="typeIdx" @change="onTypeChange">
+          <view class="picker-box">反馈类型:{{ typeList[typeIdx] }}</view>
+        </picker>
+      </view>
+      <button class="submit-btn" @click="submit">提交反馈</button>
+    </view>
+    <view class="history-title">历史反馈</view>
+    <view v-if="history.length === 0" class="empty-history">暂无反馈记录</view>
+    <view v-else class="history-list">
+      <view class="history-item" v-for="item in history" :key="item.id">
+        <view class="history-type">[{{ item.type }}]</view>
+        <view class="history-content">{{ item.content }}</view>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      content: '',
+      typeList: ['功能建议', '内容问题', 'BUG反馈', '其他'],
+      typeIdx: 0,
+      history: []
+    }
+  },
+  methods: {
+    onTypeChange(e) {
+      this.typeIdx = e.detail.value
+    },
+    submit() {
+      if (!this.content) {
+        uni.showToast({ title: '请填写反馈内容', icon: 'none' })
+        return
+      }
+      this.history.unshift({
+        id: Date.now(),
+        type: this.typeList[this.typeIdx],
+        content: this.content
+      })
+      this.content = ''
+      uni.showToast({ title: '反馈已提交', icon: 'success' })
+    }
+  }
+}
+</script>
+<style lang="scss">
+.feedback-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.feedback-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.feedback-form {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx 32rpx 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  padding: 32rpx 24rpx;
+}
+.form-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 24rpx;
+}
+.form-icon {
+  width: 48rpx;
+  height: 48rpx;
+  margin-right: 16rpx;
+}
+.form-input {
+  flex: 1;
+  border: none;
+  font-size: 28rpx;
+  background: #f7f8fa;
+  border-radius: 8rpx;
+  padding: 16rpx;
+}
+.picker-box {
+  font-size: 28rpx;
+  color: #409EFF;
+  background: #f7f8fa;
+  border-radius: 8rpx;
+  padding: 16rpx 24rpx;
+}
+.submit-btn {
+  width: 100%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+}
+.history-title {
+  font-size: 28rpx;
+  color: #888;
+  margin: 32rpx 0 16rpx 32rpx;
+}
+.empty-history {
+  color: #bbb;
+  font-size: 26rpx;
+  text-align: center;
+  margin-top: 32rpx;
+}
+.history-list {
+  margin: 0 24rpx;
+}
+.history-item {
+  background: #fff;
+  border-radius: 12rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
+  padding: 20rpx 24rpx;
+  margin-bottom: 18rpx;
+  display: flex;
+  align-items: center;
+}
+.history-type {
+  color: #409EFF;
+  font-size: 24rpx;
+  margin-right: 16rpx;
+}
+.history-content {
+  font-size: 26rpx;
+  color: #333;
+}
+</style> 

+ 217 - 0
pages/mine/index.vue

@@ -0,0 +1,217 @@
+<template>
+  <view class="container">
+    <!-- 个人信息卡片 -->
+    <view class="profile-card">
+      <image class="avatar" :src="avatarUrl" mode="aspectFill" />
+      <view class="profile-info">
+		<view class="phone">{{ nickname }}</view>
+        <view class="phone">{{ phone }}</view>
+        <view class="profile-link" @click="goToProfile">个人信息 ></view>
+      </view>
+    </view>
+
+    <!-- 我的学习模块 -->
+    <view class="section">
+      <view class="section-title">我的学习</view>
+      <view class="study-row">
+        <view class="study-card" v-for="item in studyList" :key="item.title" @click="goTo(item.path)">
+          <image :src="item.icon" class="study-icon" />
+          <view class="study-title">{{ item.title }}</view>
+        </view>
+      </view>
+    </view>
+    <view class="section list-section">
+      <!-- <view class="section-title">商家店铺后台</view> -->
+      <view class="menu-list-vertical">
+        <view v-for="(item, idx) in menuList" :key="item.title">
+          <view class="menu-item-vertical" @click="goTo(item.path)">
+            <image :src="item.icon" class="menu-icon-vertical" />
+            <view class="menu-title-vertical">{{ item.title }}</view>
+            <text class="arrow">›</text>
+          </view>
+          <view v-if="idx !== menuList.length-1" class="divider"></view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      avatarUrl: '',
+      phone: '',
+	  nickname:'',
+      studyList: [
+        { title: '日历', icon: '/static/calender.png', path: '/pages/calendar/index' },
+        { title: '我的下载', icon: '/static/xiazai.png', path: '/pages/search/index' },
+        { title: '错题本', icon: '/static/cuotiben.png', path: '/pages/search/index' },
+        { title: '超级会员', icon: '/static/supperhuiyuan.png', path: '/pages/discover/index' },
+        { title: '订阅店铺', icon: '/static/dingyuedianpu.png', path: '/pages/discover/index' },
+      ],
+      menuList: [
+		  // <!-- 商家后台模块 -->
+		{ title: '商家店铺后台', icon: '/static/shangjiadianpu.png', path: '/pages/mine/Merchant' },
+        { title: '回收站', icon: '/static/huishouzhan.png', path: '/pages/mine/recycle' },
+        { title: '通知设置', icon: '/static/tongzhi.png', path: '/pages/mine/notify' },
+        { title: '意见反馈', icon: '/static/yijianfankui.png', path: '/pages/mine/feedback' },
+        { title: '在线客服', icon: '/static/kefu.png', path: '/pages/mine/service' },
+        { title: '了解小鹅通', icon: '/static/liaojie.png', path: '/pages/mine/about' },
+        { title: '设置', icon: '/static/shezhi.png', path: '/pages/mine/setting' },
+      ]
+    }
+  },
+  onLoad() {
+    this.getUid()
+  },
+  methods: {
+    goToProfile() {
+      uni.navigateTo({ url: '/pages/mine/profile' })
+    },
+    goTo(path) {
+      uni.navigateTo({ url: path })
+    },
+    async getUid() {
+      // 假设 uid 存在本地缓存(如登录后存储),否则请根据实际情况获取
+      try {
+        const res = await uni.request({
+          url: "http://localhost:9527/api/getUid",
+          method: 'GET'
+        })
+		console.log(res)
+        if (res.statusCode === 200) {
+			this.nickname=res.data.data.nickname
+          this.avatarUrl = res.data.data.avatarUrl
+          this.phone = res.data.data.phone
+        } else {
+          this.avatarUrl = this.defaultAvatar
+          this.phone = '获取失败'
+        }
+      } catch (e) {
+        this.avatarUrl = this.defaultAvatar
+        this.phone = '网络错误'
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+  padding-top: 80rpx;
+}
+.profile-card {
+  display: flex;
+  align-items: center;
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx 24rpx 24rpx;
+  padding: 32rpx 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+}
+.avatar {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 50%;
+  margin-right: 32rpx;
+  border: 2rpx solid #eee;
+}
+.profile-info {
+  flex: 1;
+}
+.phone {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+}
+.profile-link {
+  color: #409EFF;
+  font-size: 28rpx;
+  margin-top: 8rpx;
+  cursor: pointer;
+}
+.section {
+  margin: 0 24rpx 24rpx 24rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  padding: 24rpx 0 0 0;
+}
+.section-title {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #333;
+  margin-left: 32rpx;
+  margin-bottom: 16rpx;
+}
+.study-row {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  padding: 0 24rpx 24rpx 24rpx;
+}
+.study-card {
+  flex: 1;
+  margin: 0 8rpx;
+  background: #f8fafc;
+  border-radius: 16rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 24rpx 0 16rpx 0;
+  cursor: pointer;
+  transition: box-shadow 0.2s;
+}
+.study-card:active {
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08);
+}
+.study-icon {
+  width: 56rpx;
+  height: 56rpx;
+  margin-bottom: 8rpx;
+}
+.study-title {
+  font-size: 24rpx;
+  color: #555;
+}
+.list-section {
+  padding-bottom: 0;
+}
+.menu-list-vertical {
+  margin: 0 0 0 0;
+}
+.menu-item-vertical {
+  display: flex;
+  align-items: center;
+  padding: 0 32rpx;
+  height: 96rpx;
+  background: #fff;
+  cursor: pointer;
+  position: relative;
+}
+.menu-icon-vertical {
+  width: 40rpx;
+  height: 40rpx;
+  margin-right: 24rpx;
+}
+.menu-title-vertical {
+  flex: 1;
+  font-size: 28rpx;
+  color: #333;
+}
+.arrow {
+  color: #bbb;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+}
+.divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0 32rpx;
+}
+</style> 

+ 73 - 0
pages/mine/notify.vue

@@ -0,0 +1,73 @@
+<template>
+  <view class="notify-container">
+    <view class="notify-title">通知设置</view>
+    <view class="notify-list">
+      <view class="notify-item">
+        <view class="item-label">消息推送</view>
+        <switch class="item-switch" :checked="notifyPush" @change="val=>notifyPush=val.detail.value" color="#409EFF" />
+      </view>
+      <view class="divider"></view>
+      <view class="notify-item">
+        <view class="item-label">声音提醒</view>
+        <switch class="item-switch" :checked="sound" @change="val=>sound=val.detail.value" color="#409EFF" />
+      </view>
+      <view class="divider"></view>
+      <view class="notify-item">
+        <view class="item-label">系统通知</view>
+        <switch class="item-switch" :checked="sysNotify" @change="val=>sysNotify=val.detail.value" color="#409EFF" />
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      notifyPush: true,
+      sound: true,
+      sysNotify: false
+    }
+  }
+}
+</script>
+<style lang="scss">
+.notify-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 0 0 120rpx 0;
+}
+.notify-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+  background: #f7f8fa;
+}
+.notify-list {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  overflow: hidden;
+}
+.notify-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 32rpx 32rpx;
+  background: #fff;
+}
+.item-label {
+  font-size: 30rpx;
+  color: #333;
+}
+.item-switch {
+  transform: scale(0.9);
+}
+.divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0 32rpx;
+}
+</style> 

+ 241 - 0
pages/mine/profile.vue

@@ -0,0 +1,241 @@
+<template>
+  <view class="profile-container">
+    <view class="profile-header">个人信息</view>
+    <view class="profile-list">
+      <!-- 头像 -->
+      <view class="profile-item" @click="chooseAvatar">
+        <view class="item-label">头像</view>
+        <image class="avatar" :src="avatarUrl" mode="aspectFill" />
+        <text class="arrow">›</text>
+      </view>
+      <!-- 昵称 -->
+      <view class="profile-item" @click="editNickname">
+        <view class="item-label">昵称</view>
+        <view class="item-value">{{ nickname }}</view>
+        <text class="arrow">›</text>
+      </view>
+      <!-- 更换手机号 -->
+      <view class="profile-item" @click="goToChangePhone">
+        <view class="item-label">更换手机号</view>
+        <view class="item-value">{{ phone }}</view>
+        <text class="arrow">›</text>
+      </view>
+      <!-- 微信绑定(可选) -->
+      <view class="profile-item" @click="goToUnbindWechat">
+        <view class="item-label">解绑微信</view>
+        <image src="/static/wechat.png" class="wechat-icon" />
+        <view class="item-value">{{ wechatName }}</view>
+        <text class="arrow">›</text>
+      </view>
+      <!-- 设置密码 -->
+      <view class="profile-item" @click="goToSetPassword">
+        <view class="item-label">设置密码</view>
+        <text class="arrow">›</text>
+      </view>
+      <!-- 账号注销 -->
+      <view class="profile-item" @click="goToCancelAccount">
+        <view class="item-label">账号注销</view>
+        <text class="arrow">›</text>
+      </view>
+    </view>
+    <!-- 昵称编辑弹窗 -->
+    <view v-if="showNicknamePopup" class="popup-mask">
+      <view class="popup-content">
+        <input v-model="editNicknameValue" placeholder="请输入新昵称" />
+        <view class="popup-btns">
+          <button @click="showNicknamePopup=false">取消</button>
+          <button @click="saveNickname">保存</button>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      avatarUrl: '',
+      nickname: '',
+      phone: '',
+      wechatName: '',
+      editNicknameValue: '',
+      showNicknamePopup: false
+    }
+  },
+  onLoad() {
+    this.getUserInfo()
+  },
+  methods: {
+    async getUserInfo() {
+      const uid = uni.getStorageSync('uid')
+      const res = await uni.request({
+        url: `http://localhost:9527/api/getUid?uid=${uid}`,
+        method: 'GET'
+      })
+      if (res.statusCode === 200 && res.data.code === 200) {
+        const data = res.data.data
+        this.avatarUrl = data.avatarUrl
+        this.nickname = data.nickname
+        this.phone = data.phone
+        this.wechatName = data.wechatName || ''
+      }
+    },
+    // 选择并上传头像
+    chooseAvatar() {
+      uni.chooseImage({
+        count: 1,
+        success: async (chooseRes) => {
+          const filePath = chooseRes.tempFilePaths[0]
+          // 这里假设你有后端/OSS直传接口
+          const uploadRes = await uni.uploadFile({
+            url: '你的OSS上传接口', // TODO: 替换为你的OSS上传接口
+            filePath,
+            name: 'file'
+          })
+          // 上传成功后,更新头像
+          const avatarUrl = JSON.parse(uploadRes.data).url
+          await uni.request({
+            url: 'http://localhost:9527/api/updateUser',
+            method: 'POST',
+            data: { uid: uni.getStorageSync('uid'), avatarUrl }
+          })
+          this.avatarUrl = avatarUrl
+          uni.showToast({ title: '头像已更新', icon: 'success' })
+        }
+      })
+    },
+    // 编辑昵称
+    editNickname() {
+      this.editNicknameValue = this.nickname
+      this.showNicknamePopup = true
+    },
+    async saveNickname() {
+      await uni.request({
+        url: 'http://localhost:9527/api/updateUser',
+        method: 'POST',
+        data: { uid: uni.getStorageSync('uid'), nickname: this.editNicknameValue }
+      })
+      this.nickname = this.editNicknameValue
+      this.showNicknamePopup = false
+      uni.showToast({ title: '昵称已更新', icon: 'success' })
+    },
+    // 跳转更换手机号
+    goToChangePhone() {
+      uni.navigateTo({ url: '/pages/mine/changePhone' })
+    },
+    // 跳转设置密码
+    goToSetPassword() {
+      uni.navigateTo({ url: '/pages/mine/setPassword' })
+    },
+    // 跳转账号注销
+    goToCancelAccount() {
+      uni.navigateTo({ url: '/pages/mine/cancelAccount' })
+    },
+    // 跳转解绑微信
+    goToUnbindWechat() {
+      uni.navigateTo({ url: '/pages/mine/unbindWechat' })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.profile-container {
+  background: #f7f8fa;
+  min-height: 100vh;
+}
+.profile-header {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  padding: 40rpx 0 20rpx 0;
+  background: #fff;
+}
+.profile-list {
+  margin-top: 20rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  overflow: hidden;
+}
+.profile-item {
+  display: flex;
+  align-items: center;
+  padding: 0 32rpx;
+  height: 100rpx;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+.profile-item:last-child {
+  border-bottom: none;
+}
+.item-label {
+  flex: 0 0 180rpx;
+  color: #333;
+  font-size: 30rpx;
+}
+.item-value {
+  flex: 1;
+  color: #666;
+  font-size: 28rpx;
+  text-align: right;
+  margin-right: 16rpx;
+}
+.avatar {
+  width: 70rpx;
+  height: 70rpx;
+  border-radius: 50%;
+  margin-left: auto;
+  margin-right: 8rpx;
+  background: #eee;
+}
+.wechat-icon {
+  width: 36rpx;
+  height: 36rpx;
+  margin-right: 8rpx;
+}
+.arrow {
+  color: #bbb;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+}
+.popup-mask {
+  position: fixed;
+  left: 0; right: 0; top: 0; bottom: 0;
+  background: rgba(0,0,0,0.3);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+.popup-content {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 40rpx;
+  min-width: 400rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.popup-content input {
+  width: 300rpx;
+  border: 1rpx solid #eee;
+  border-radius: 8rpx;
+  padding: 16rpx;
+  margin-bottom: 24rpx;
+}
+.popup-btns {
+  display: flex;
+  width: 100%;
+  justify-content: space-between;
+}
+.popup-btns button {
+  flex: 1;
+  margin: 0 8rpx;
+  background: #409EFF;
+  color: #fff;
+  border: none;
+  border-radius: 8rpx;
+  padding: 16rpx 0;
+  font-size: 28rpx;
+}
+</style> 

+ 95 - 0
pages/mine/recycle.vue

@@ -0,0 +1,95 @@
+<template>
+  <view class="recycle-container">
+    <view class="recycle-title">回收站</view>
+    <view v-if="items.length === 0" class="empty-box">
+      <image src="/static/logo.png" class="empty-img" />
+      <view class="empty-tip">暂无已删除内容</view>
+    </view>
+    <view v-else class="recycle-list">
+      <view class="recycle-item" v-for="item in items" :key="item.id">
+        <image :src="item.icon" class="item-icon" />
+        <view class="item-info">
+          <view class="item-title">{{ item.title }}</view>
+          <view class="item-desc">{{ item.desc }}</view>
+        </view>
+        <button class="restore-btn">还原</button>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      items: [] // 可模拟 [{id:1,title:'文档A',desc:'2024-06-01删除',icon:'/static/logo.png'}]
+    }
+  }
+}
+</script>
+<style lang="scss">
+.recycle-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.recycle-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.empty-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-top: 120rpx;
+}
+.empty-img {
+  width: 160rpx;
+  height: 160rpx;
+  margin-bottom: 32rpx;
+  opacity: 0.7;
+}
+.empty-tip {
+  color: #bbb;
+  font-size: 28rpx;
+}
+.recycle-list {
+  margin: 0 24rpx;
+}
+.recycle-item {
+  display: flex;
+  align-items: center;
+  background: #fff;
+  border-radius: 16rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  padding: 24rpx;
+  margin-bottom: 24rpx;
+}
+.item-icon {
+  width: 64rpx;
+  height: 64rpx;
+  margin-right: 24rpx;
+}
+.item-info {
+  flex: 1;
+}
+.item-title {
+  font-size: 30rpx;
+  color: #222;
+  font-weight: 600;
+}
+.item-desc {
+  font-size: 24rpx;
+  color: #888;
+  margin-top: 8rpx;
+}
+.restore-btn {
+  background: #409EFF;
+  color: #fff;
+  border-radius: 10rpx;
+  font-size: 26rpx;
+  padding: 12rpx 28rpx;
+}
+</style> 

+ 65 - 0
pages/mine/service.vue

@@ -0,0 +1,65 @@
+<template>
+  <view class="service-container">
+    <view class="service-title">在线客服</view>
+    <view class="service-box">
+      <image src="/static/logo.png" class="service-avatar" />
+      <view class="service-welcome">您好,有任何问题可随时联系小鹅客服!</view>
+      <button class="faq-btn">常见问题</button>
+      <button class="contact-btn">联系客服</button>
+    </view>
+  </view>
+</template>
+<script>
+export default {}
+</script>
+<style lang="scss">
+.service-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.service-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.service-box {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 48rpx 24rpx 48rpx 24rpx;
+}
+.service-avatar {
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 50%;
+  margin-bottom: 24rpx;
+}
+.service-welcome {
+  font-size: 28rpx;
+  color: #555;
+  margin-bottom: 32rpx;
+  text-align: center;
+}
+.faq-btn {
+  width: 80%;
+  background: #f7f8fa;
+  color: #409EFF;
+  border-radius: 12rpx;
+  font-size: 28rpx;
+  margin-bottom: 18rpx;
+}
+.contact-btn {
+  width: 80%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+}
+</style> 

+ 93 - 0
pages/mine/setPassword.vue

@@ -0,0 +1,93 @@
+<template>
+  <view class="set-password-container">
+    <view class="header">设置密码</view>
+    <view class="form">
+      <input v-model="password" type="password" placeholder="请输入新密码" class="input" />
+      <input v-model="confirmPassword" type="password" placeholder="请确认新密码" class="input" />
+      <button class="submit-btn" @click="submit">确认设置</button>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      password: '',
+      confirmPassword: ''
+    }
+  },
+  methods: {
+    submit() {
+      if (!this.password || this.password.length < 6) {
+        uni.showToast({ title: '密码至少6位', icon: 'none' })
+        return
+      }
+      if (this.password !== this.confirmPassword) {
+        uni.showToast({ title: '两次密码不一致', icon: 'none' })
+        return
+      }
+      uni.request({
+        url: 'http://localhost:9527/api/setPassword',
+        method: 'POST',
+        data: {
+          uid: uni.getStorageSync('uid'),
+          password: this.password
+        },
+        success: (res) => {
+          if (res.statusCode === 200 && res.data.code === 200) {
+            uni.showToast({ title: '设置成功', icon: 'success' })
+            setTimeout(() => uni.navigateBack(), 1000)
+          } else {
+            uni.showToast({ title: res.data.message || '设置失败', icon: 'none' })
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.set-password-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+}
+.header {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+}
+.form {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 32rpx;
+  padding: 40rpx 32rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  display: flex;
+  flex-direction: column;
+  gap: 32rpx;
+}
+.input {
+  width: 100%;
+  height: 80rpx;
+  border: 1rpx solid #eee;
+  border-radius: 12rpx;
+  padding: 0 24rpx;
+  font-size: 30rpx;
+  background: #f7f8fa;
+}
+.submit-btn {
+  width: 100%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}
+</style> 

+ 108 - 0
pages/mine/setting.vue

@@ -0,0 +1,108 @@
+<template>
+  <view class="setting-container">
+    <view class="setting-title">设置</view>
+    <view class="setting-list">
+      <view class="setting-item" v-for="item in settingList" :key="item.title" @click="onItem(item)">
+        <image :src="item.icon" class="item-icon" />
+        <view class="item-title">{{ item.title }}</view>
+        <text class="arrow">›</text>
+      </view>
+      <view class="divider" v-for="(item,idx) in settingList" :key="'d'+idx" v-if="idx!==settingList.length-1"></view>
+    </view>
+    <button class="logout-btn" @click="logout">退出登录</button>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      settingList: [
+        { title: '账号安全', icon: '/static/logo.png' },
+        { title: '隐私设置', icon: '/static/2.png' },
+        { title: '清除缓存', icon: '/static/login.png' },
+        { title: '关于我们', icon: '/static/logo.png' }
+      ]
+    }
+  },
+  methods: {
+    onItem(item) {
+      if(item.title==='清除缓存'){
+        uni.clearStorageSync();
+        uni.showToast({ title: '缓存已清除', icon: 'success' })
+      } else {
+        uni.showToast({ title: item.title, icon: 'none' })
+      }
+    },
+    logout() {
+      uni.showModal({
+        title: '提示',
+        content: '确定要退出登录吗?',
+        success: (res) => {
+          if (res.confirm) {
+            uni.clearStorageSync();
+            uni.reLaunch({ url: '/pages/login/index' })
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+<style lang="scss">
+.setting-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.setting-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.setting-list {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  overflow: hidden;
+}
+.setting-item {
+  display: flex;
+  align-items: center;
+  padding: 0 32rpx;
+  height: 96rpx;
+  background: #fff;
+  cursor: pointer;
+  position: relative;
+}
+.item-icon {
+  width: 40rpx;
+  height: 40rpx;
+  margin-right: 24rpx;
+}
+.item-title {
+  flex: 1;
+  font-size: 28rpx;
+  color: #333;
+}
+.arrow {
+  color: #bbb;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+}
+.divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0 32rpx;
+}
+.logout-btn {
+  width: 80%;
+  margin: 48rpx 10% 0 10%;
+  background: #ff4d4f;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+}
+</style> 

+ 82 - 0
pages/mine/unbindWechat.vue

@@ -0,0 +1,82 @@
+<template>
+  <view class="unbind-wechat-container">
+    <view class="header">解绑微信</view>
+    <view class="desc">当前绑定微信:{{ wechatName }}</view>
+    <button class="submit-btn" type="warn" @click="submit">确认解绑</button>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      wechatName: ''
+    }
+  },
+  onLoad() {
+    // 假设已存储微信名
+    this.wechatName = uni.getStorageSync('wechatName') || '未绑定'
+  },
+  methods: {
+    submit() {
+      uni.showModal({
+        title: '确认解绑',
+        content: '解绑后将无法使用微信快捷登录,是否继续?',
+        success: (res) => {
+          if (res.confirm) {
+            uni.request({
+              url: 'http://localhost:9527/api/unbindWechat',
+              method: 'POST',
+              data: { uid: uni.getStorageSync('uid') },
+              success: (res) => {
+                if (res.statusCode === 200 && res.data.code === 200) {
+                  uni.showToast({ title: '解绑成功', icon: 'success' })
+                  setTimeout(() => uni.navigateBack(), 1000)
+                } else {
+                  uni.showToast({ title: res.data.message || '解绑失败', icon: 'none' })
+                }
+              }
+            })
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.unbind-wechat-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.header {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+  width: 100%;
+}
+.desc {
+  font-size: 28rpx;
+  color: #333;
+  margin: 60rpx 0 40rpx 0;
+  text-align: center;
+  padding: 0 32rpx;
+}
+.submit-btn {
+  width: 80%;
+  background: #e74c3c;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}
+</style> 

+ 49 - 0
pages/search/index.vue

@@ -0,0 +1,49 @@
+<template>
+  <view class="search-page">
+    <view class="search-bar">
+      <input v-model="searchText" placeholder="搜索课程" @confirm="onSearch" />
+      <button @click="onSearch">搜索</button>
+    </view>
+    <view v-if="results.length" class="result-list">
+      <view v-for="item in results" :key="item.id" class="result-item">
+        <view class="title">{{ item.title }}</view>
+        <view class="desc">{{ item.desc }}</view>
+      </view>
+    </view>
+    <view v-else class="empty">暂无搜索结果</view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      searchText: '',
+      results: []
+    }
+  },
+  methods: {
+    onSearch() {
+      // 模拟搜索
+      if (this.searchText) {
+        this.results = [
+          { id: 1, title: '示例课程A', desc: '课程描述A' },
+          { id: 2, title: '示例课程B', desc: '课程描述B' }
+        ]
+      } else {
+        this.results = []
+      }
+    }
+  }
+}
+</script>
+<style scoped>
+.search-page { padding: 40rpx; }
+.search-bar { display: flex; gap: 16rpx; margin-bottom: 32rpx; }
+input { flex: 1; border: 1px solid #eee; border-radius: 8rpx; padding: 16rpx; font-size: 30rpx; }
+button { background: #3498db; color: #fff; border: none; border-radius: 8rpx; padding: 0 32rpx; font-size: 30rpx; }
+.result-list { margin-top: 24rpx; }
+.result-item { background: #f7f8fa; border-radius: 12rpx; padding: 24rpx; margin-bottom: 16rpx; }
+.title { font-size: 32rpx; font-weight: 600; color: #222; }
+.desc { font-size: 26rpx; color: #888; }
+.empty { text-align: center; color: #bbb; font-size: 28rpx; margin-top: 80rpx; }
+</style> 

BIN
static/1.jpg


BIN
static/2.png


BIN
static/calender.png


BIN
static/cuotiben.png


BIN
static/dingyuedianpu.png


BIN
static/huishouzhan.png


BIN
static/kefu.png


BIN
static/liaojie.png


BIN
static/msg1.png


BIN
static/msg2.png


BIN
static/msg3.png


BIN
static/msg4.png


BIN
static/shangjiadianpu.png


BIN
static/shezhi.png


BIN
static/supperhuiyuan.png


BIN
static/tabbar/discover.png


BIN
static/tabbar/discover_selected.png


BIN
static/tabbar/home.png


BIN
static/tabbar/home_selected.png


BIN
static/tabbar/message.png


BIN
static/tabbar/message_selected.png


BIN
static/tabbar/mine.png


BIN
static/tabbar/mine_selected.png


BIN
static/tongzhi.png


BIN
static/xiazai.png


BIN
static/yijianfankui.png


+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/calendar/index.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY2FsZW5kYXIvaW5kZXgudnVl"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/calendar/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/course/detail.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"detail.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvY291cnNlL2RldGFpbC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/course/detail.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/discover/index.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvZGlzY292ZXIvaW5kZXgudnVl"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/discover/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/message/index.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWVzc2FnZS9pbmRleC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/message/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/message/selected.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"selected.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWVzc2FnZS9zZWxlY3RlZC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/message/selected.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/Merchant.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"Merchant.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9NZXJjaGFudC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/Merchant.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/about.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"about.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9hYm91dC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/about.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/cancelAccount.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"cancelAccount.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9jYW5jZWxBY2NvdW50LnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/cancelAccount.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/changePhone.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"changePhone.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9jaGFuZ2VQaG9uZS52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/changePhone.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/feedback.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"feedback.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9mZWVkYmFjay52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/feedback.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/index.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9pbmRleC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/notify.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"notify.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9ub3RpZnkudnVl"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/notify.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/profile.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"profile.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9wcm9maWxlLnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/profile.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/recycle.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"recycle.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9yZWN5Y2xlLnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/recycle.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/service.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"service.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9zZXJ2aWNlLnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/service.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/setPassword.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"setPassword.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9zZXRQYXNzd29yZC52dWU"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/setPassword.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/setting.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"setting.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS9zZXR0aW5nLnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/setting.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/mine/unbindWechat.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"unbindWechat.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbWluZS91bmJpbmRXZWNoYXQudnVl"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/mine/unbindWechat.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 1 - 0
unpackage/dist/dev/.sourcemap/mp-weixin/pages/search/index.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sources":["../../../ruanjian/HBuilder X/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvc2VhcmNoL2luZGV4LnZ1ZQ"],"sourcesContent":["import MiniProgramPage from 'D:/java file/2407_5/small_goose_vue/pages/search/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

+ 65 - 0
unpackage/dist/dev/mp-weixin/pages/calendar/index.js

@@ -0,0 +1,65 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  data() {
+    return {
+      weeks: ["日", "一", "二", "三", "四", "五", "六"],
+      calendarRows: this.getCalendarRows()
+    };
+  },
+  methods: {
+    getCalendarRows() {
+      const d = /* @__PURE__ */ new Date();
+      const year = d.getFullYear();
+      const month = d.getMonth();
+      const firstDay = new Date(year, month, 1).getDay();
+      const days = new Date(year, month + 1, 0).getDate();
+      const rows = [];
+      let row = new Array(7).fill(0);
+      let day = 1;
+      for (let i = 0; i < 6; i++) {
+        for (let j = 0; j < 7; j++) {
+          if (i === 0 && j < firstDay)
+            continue;
+          if (day > days)
+            break;
+          row[j] = day++;
+        }
+        rows.push([...row]);
+        row = new Array(7).fill(0);
+        if (day > days)
+          break;
+      }
+      return rows;
+    },
+    isToday(d) {
+      const now = /* @__PURE__ */ new Date();
+      return d === now.getDate();
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return {
+    a: common_vendor.f($data.weeks, (w, k0, i0) => {
+      return {
+        a: common_vendor.t(w),
+        b: w
+      };
+    }),
+    b: common_vendor.f($data.calendarRows, (row, i, i0) => {
+      return {
+        a: common_vendor.f(row, (d, k1, i1) => {
+          return {
+            a: common_vendor.t(d > 0 ? d : ""),
+            b: d,
+            c: $options.isToday(d) ? 1 : ""
+          };
+        }),
+        b: i
+      };
+    })
+  };
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3ceb4997"]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/calendar/index.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/calendar/index.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "课程日历",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/calendar/index.wxml

@@ -0,0 +1 @@
+<view class="calendar-page data-v-3ceb4997"><view class="calendar-header data-v-3ceb4997"><text class="calendar-title data-v-3ceb4997">课程日历</text></view><view class="calendar-content data-v-3ceb4997"><view class="calendar-row calendar-week data-v-3ceb4997"><text wx:for="{{a}}" wx:for-item="w" wx:key="b" class="data-v-3ceb4997">{{w.a}}</text></view><view wx:for="{{b}}" wx:for-item="row" wx:key="b" class="calendar-row data-v-3ceb4997"><text wx:for="{{row.a}}" wx:for-item="d" wx:key="b" class="{{['data-v-3ceb4997', d.c && 'today']}}">{{d.a}}</text></view></view></view>

+ 17 - 0
unpackage/dist/dev/mp-weixin/pages/calendar/index.wxss

@@ -0,0 +1,17 @@
+
+.calendar-page.data-v-3ceb4997 { padding: 40rpx;
+}
+.calendar-header.data-v-3ceb4997 { text-align: center; margin-bottom: 32rpx;
+}
+.calendar-title.data-v-3ceb4997 { font-size: 36rpx; font-weight: bold; color: #3498db;
+}
+.calendar-content.data-v-3ceb4997 { background: #fff; border-radius: 16rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04); padding: 24rpx;
+}
+.calendar-row.data-v-3ceb4997 { display: flex; justify-content: space-between; margin-bottom: 8rpx;
+}
+.calendar-week text.data-v-3ceb4997 { color: #888; font-size: 28rpx; flex: 1; text-align: center;
+}
+.calendar-row text.data-v-3ceb4997 { flex: 1; text-align: center; font-size: 30rpx; color: #222; padding: 8rpx 0; border-radius: 8rpx;
+}
+.today.data-v-3ceb4997 { background: #3498db; color: #fff;
+}

+ 124 - 0
unpackage/dist/dev/mp-weixin/pages/course/detail.js

@@ -0,0 +1,124 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const common_assets = require("../../common/assets.js");
+const _sfc_main = {
+  data() {
+    return {
+      course: {},
+      comments: [],
+      catalog: [],
+      tabIndex: 0,
+      defaultCover: "/static/default-course.png",
+      defaultAvatar: "/static/1.jpg",
+      lockIcon: "/static/lock.png"
+    };
+  },
+  computed: {
+    parsedImages() {
+      try {
+        if (this.course.images) {
+          return JSON.parse(this.course.images);
+        }
+        return [];
+      } catch (e) {
+        common_vendor.index.__f__("error", "at pages/course/detail.vue:108", "解析图片数据失败:", e);
+        return [];
+      }
+    }
+  },
+  onLoad(options) {
+    this.fetchDetail(options.id);
+  },
+  methods: {
+    async fetchDetail(id) {
+      try {
+        const res = await common_vendor.index.request({
+          url: `http://localhost:9527/product/findOne?productId=${id}`,
+          method: "GET"
+        });
+        if (res.statusCode === 200) {
+          this.course = res.data.data;
+          this.comments = res.data.data.comments || [];
+          this.catalog = res.data.data.catalog || [];
+        } else {
+          throw new Error(res.data.message || "获取数据失败");
+        }
+      } catch (err) {
+        common_vendor.index.showToast({
+          title: err.message || "加载失败",
+          icon: "none"
+        });
+      }
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  var _a, _b;
+  return common_vendor.e({
+    a: common_vendor.f($options.parsedImages, (image, index, i0) => {
+      return {
+        a: image.imageUrl,
+        b: index
+      };
+    }),
+    b: common_vendor.t($data.course.name),
+    c: common_vendor.t($data.course.subtitle),
+    d: common_vendor.t((_a = $data.course.price) == null ? void 0 : _a.toFixed(2)),
+    e: common_vendor.t((_b = $data.course.originalPrice) == null ? void 0 : _b.toFixed(2)),
+    f: common_vendor.t($data.course.stock),
+    g: common_vendor.t($data.comments.length),
+    h: $data.comments.length === 0
+  }, $data.comments.length === 0 ? {} : {
+    i: common_vendor.f($data.comments, (item, k0, i0) => {
+      return {
+        a: item.avatar || $data.defaultAvatar,
+        b: common_vendor.t(item.user),
+        c: common_vendor.f(5, (n, k1, i1) => {
+          return {
+            a: n,
+            b: n <= item.star ? 1 : ""
+          };
+        }),
+        d: common_vendor.t(item.content || "此用户没有填写评价"),
+        e: item.id
+      };
+    })
+  }, {
+    j: common_vendor.n($data.tabIndex === 0 ? "active" : ""),
+    k: common_vendor.o(($event) => $data.tabIndex = 0),
+    l: common_vendor.n($data.tabIndex === 1 ? "active" : ""),
+    m: common_vendor.o(($event) => $data.tabIndex = 1),
+    n: common_vendor.n($data.tabIndex === 2 ? "active" : ""),
+    o: common_vendor.o(($event) => $data.tabIndex = 2),
+    p: $data.tabIndex === 0
+  }, $data.tabIndex === 0 ? {
+    q: common_vendor.f($options.parsedImages, (image, index, i0) => {
+      return {
+        a: image.imageUrl,
+        b: common_vendor.t(image.courseTitle),
+        c: common_vendor.t(image.courseDesc),
+        d: index
+      };
+    })
+  } : $data.tabIndex === 1 ? {
+    s: common_vendor.f($data.catalog, (item, k0, i0) => {
+      return common_vendor.e({
+        a: item.icon || $data.lockIcon,
+        b: common_vendor.t(item.title),
+        c: common_vendor.t(item.type),
+        d: common_vendor.t(item.date),
+        e: common_vendor.t(item.count),
+        f: item.trial
+      }, item.trial ? {} : {}, {
+        g: item.id
+      });
+    })
+  } : {
+    t: common_assets._imports_0$5
+  }, {
+    r: $data.tabIndex === 1
+  });
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3d21314d"]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/course/detail.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/course/detail.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "课程详情",
+  "usingComponents": {}
+}

File diff suppressed because it is too large
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/course/detail.wxml


+ 237 - 0
unpackage/dist/dev/mp-weixin/pages/course/detail.wxss

@@ -0,0 +1,237 @@
+
+.course-detail-container.data-v-3d21314d {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.swiper.data-v-3d21314d {
+  width: 100%;
+  height: 500rpx;
+}
+.swiper-image.data-v-3d21314d {
+  width: 100%;
+  height: 100%;
+}
+.header.data-v-3d21314d {
+  background: #fff;
+  padding: 24rpx;
+  margin-bottom: 20rpx;
+}
+.title.data-v-3d21314d {
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 12rpx;
+}
+.subtitle.data-v-3d21314d {
+  font-size: 28rpx;
+  color: #666;
+  margin-bottom: 16rpx;
+}
+.price-row.data-v-3d21314d {
+  display: flex;
+  align-items: baseline;
+  margin-bottom: 12rpx;
+}
+.price.data-v-3d21314d {
+  color: #ff6600;
+  font-size: 40rpx;
+  font-weight: bold;
+  margin-right: 16rpx;
+}
+.original-price.data-v-3d21314d {
+  color: #999;
+  font-size: 28rpx;
+  text-decoration: line-through;
+}
+.stock.data-v-3d21314d {
+  font-size: 26rpx;
+  color: #666;
+}
+.section.data-v-3d21314d {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 24rpx 24rpx 0 24rpx;
+  padding: 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+}
+.section-title.data-v-3d21314d {
+  font-size: 28rpx;
+  font-weight: bold;
+  margin-bottom: 16rpx;
+}
+.empty-comment.data-v-3d21314d {
+  color: #bbb;
+  text-align: center;
+  font-size: 26rpx;
+}
+.comment-list.data-v-3d21314d {
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+}
+.comment-item.data-v-3d21314d {
+  display: flex;
+  align-items: flex-start;
+}
+.comment-avatar.data-v-3d21314d {
+  width: 56rpx;
+  height: 56rpx;
+  border-radius: 50%;
+  margin-right: 16rpx;
+}
+.comment-main.data-v-3d21314d {
+  flex: 1;
+}
+.comment-user.data-v-3d21314d {
+  font-size: 26rpx;
+  color: #333;
+  font-weight: 600;
+}
+.comment-stars.data-v-3d21314d {
+  color: #ffb400;
+  font-size: 24rpx;
+  margin: 4rpx 0 8rpx 0;
+}
+.star.active.data-v-3d21314d {
+  color: #ffb400;
+}
+.star.data-v-3d21314d {
+  color: #eee;
+}
+.comment-content.data-v-3d21314d {
+  font-size: 24rpx;
+  color: #666;
+}
+.tabs.data-v-3d21314d {
+  display: flex;
+  background: #fff;
+  padding: 0 24rpx;
+  border-bottom: 1rpx solid #eee;
+}
+.tab.data-v-3d21314d {
+  flex: 1;
+  text-align: center;
+  padding: 24rpx 0;
+  font-size: 30rpx;
+  color: #666;
+  position: relative;
+}
+.tab.active.data-v-3d21314d {
+  color: #ff6600;
+  font-weight: bold;
+}
+.tab.active.data-v-3d21314d::after {
+  content: '';
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  transform: translateX(-50%);
+  width: 40rpx;
+  height: 6rpx;
+  background: #ff6600;
+  border-radius: 3rpx;
+}
+.tab-content.data-v-3d21314d {
+  background: #fff;
+  padding: 24rpx;
+}
+.detail-section.data-v-3d21314d {
+  margin-bottom: 24rpx;
+}
+.detail-item.data-v-3d21314d {
+  margin-bottom: 30rpx;
+}
+.detail-image.data-v-3d21314d {
+  width: 100%;
+  border-radius: 12rpx;
+  margin-bottom: 16rpx;
+}
+.detail-info.data-v-3d21314d {
+  padding: 0 12rpx;
+}
+.detail-title.data-v-3d21314d {
+  font-size: 30rpx;
+  font-weight: bold;
+  margin-bottom: 8rpx;
+}
+.detail-desc.data-v-3d21314d {
+  font-size: 26rpx;
+  color: #666;
+  line-height: 1.6;
+}
+.catalog-item.data-v-3d21314d {
+  display: flex;
+  align-items: center;
+  padding: 18rpx 0;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+.catalog-icon.data-v-3d21314d {
+  width: 36rpx;
+  height: 36rpx;
+  margin-right: 16rpx;
+}
+.catalog-main.data-v-3d21314d {
+  flex: 1;
+}
+.catalog-title.data-v-3d21314d {
+  font-size: 26rpx;
+  color: #222;
+  font-weight: 600;
+}
+.catalog-meta.data-v-3d21314d {
+  font-size: 22rpx;
+  color: #888;
+  margin-top: 4rpx;
+}
+.trial.data-v-3d21314d {
+  color: #ff6600;
+  font-size: 22rpx;
+  border: 1rpx solid #ff6600;
+  border-radius: 8rpx;
+  padding: 2rpx 12rpx;
+  margin-left: 8rpx;
+}
+.empty-interact.data-v-3d21314d {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: 200rpx;
+}
+.empty-img.data-v-3d21314d {
+  width: 120rpx;
+  height: 120rpx;
+  margin-bottom: 16rpx;
+  opacity: 0.7;
+}
+.empty-tip.data-v-3d21314d {
+  color: #bbb;
+  font-size: 26rpx;
+}
+.footer.data-v-3d21314d {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  display: flex;
+  padding: 16rpx 24rpx;
+  background: #fff;
+  box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05);
+}
+.service-btn.data-v-3d21314d, .order-btn.data-v-3d21314d {
+  flex: 1;
+  height: 80rpx;
+  line-height: 80rpx;
+  text-align: center;
+  border-radius: 40rpx;
+  font-size: 28rpx;
+}
+.service-btn.data-v-3d21314d {
+  background: #f5f5f5;
+  color: #666;
+  margin-right: 20rpx;
+}
+.order-btn.data-v-3d21314d {
+  background: #ff6600;
+  color: #fff;
+}

+ 126 - 0
unpackage/dist/dev/mp-weixin/pages/discover/index.js

@@ -0,0 +1,126 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  data() {
+    return {
+      searchText: "",
+      activeTab: 0,
+      categories: [],
+      courses: [],
+      loading: false,
+      error: null,
+      defaultCover: "/static/default-course.png"
+    };
+  },
+  computed: {
+    filteredCourses() {
+      let list = this.courses;
+      if (this.activeTab !== 0) {
+        list = list.filter((c) => c.category === this.categories[this.activeTab]);
+      }
+      if (this.searchText) {
+        list = list.filter(
+          (c) => c.title.toLowerCase().includes(this.searchText.toLowerCase()) || c.description.toLowerCase().includes(this.searchText.toLowerCase())
+        );
+      }
+      common_vendor.index.__f__("log", "at pages/discover/index.vue:70", list);
+      return list;
+    }
+  },
+  onLoad() {
+    this.findAll();
+    this.findCategory();
+  },
+  methods: {
+    onSearch() {
+    },
+    async findCategory() {
+      this.loading = true;
+      this.error = null;
+      try {
+        const res = await common_vendor.index.request({
+          url: "http://localhost:9527/product/findCategory",
+          method: "GET"
+        });
+        common_vendor.index.__f__("log", "at pages/discover/index.vue:90", res.data);
+        if (res.statusCode === 200) {
+          this.categories = res.data.data;
+        } else {
+          throw new Error(res.data.message || "获取数据失败");
+        }
+      } catch (err) {
+        this.error = err.message || "网络错误,请稍后重试";
+        common_vendor.index.__f__("error", "at pages/discover/index.vue:98", "获取课程列表失败:", err);
+      } finally {
+        this.loading = false;
+      }
+    },
+    async findAll() {
+      this.loading = true;
+      this.error = null;
+      try {
+        const res = await common_vendor.index.request({
+          url: "http://localhost:9527/product/findAll",
+          method: "GET"
+        });
+        if (res.statusCode === 200) {
+          common_vendor.index.__f__("log", "at pages/discover/index.vue:113", res.data.data);
+          this.courses = res.data.data;
+        } else {
+          throw new Error(res.data.message || "获取数据失败");
+        }
+      } catch (err) {
+        this.error = err.message || "网络错误,请稍后重试";
+        common_vendor.index.__f__("error", "at pages/discover/index.vue:120", "获取课程列表失败:", err);
+      } finally {
+        this.loading = false;
+      }
+    },
+    navigateToDetail(id) {
+      common_vendor.index.__f__("log", "at pages/discover/index.vue:126", id);
+      common_vendor.index.navigateTo({
+        url: `/pages/course/detail?id=${id}`
+      });
+    }
+  }
+};
+if (!Array) {
+  const _component_uni_load_more = common_vendor.resolveComponent("uni-load-more");
+  _component_uni_load_more();
+}
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return common_vendor.e({
+    a: common_vendor.o((...args) => $options.onSearch && $options.onSearch(...args)),
+    b: $data.searchText,
+    c: common_vendor.o(($event) => $data.searchText = $event.detail.value),
+    d: common_vendor.f($data.categories, (tab, idx, i0) => {
+      return {
+        a: common_vendor.t(tab.name),
+        b: tab.id,
+        c: common_vendor.n(idx === $data.activeTab ? "active" : ""),
+        d: common_vendor.o(($event) => $data.activeTab = idx, tab.id)
+      };
+    }),
+    e: $data.loading
+  }, $data.loading ? {
+    f: common_vendor.p({
+      status: "loading"
+    })
+  } : {
+    g: common_vendor.f($data.courses, (cour, k0, i0) => {
+      var _a;
+      return {
+        a: cour.mainImage,
+        b: common_vendor.t(cour.name),
+        c: common_vendor.t(cour.description),
+        d: common_vendor.t(((_a = cour.price) == null ? void 0 : _a.toFixed(2)) || "0.00"),
+        e: common_vendor.t(cour.sales || 0),
+        f: cour.id,
+        g: common_vendor.o(($event) => $options.navigateToDetail(cour.id), cour.id)
+      };
+    })
+  });
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/discover/index.js.map

+ 5 - 0
unpackage/dist/dev/mp-weixin/pages/discover/index.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "发现",
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/discover/index.wxml

@@ -0,0 +1 @@
+<view class="container"><view class="spacer"></view><view class="search-bar"><input bindconfirm="{{a}}" placeholder="搜索课程" value="{{b}}" bindinput="{{c}}"/><text class="iconfont icon-search"></text></view><view class="category-tabs"><view wx:for="{{d}}" wx:for-item="tab" wx:key="b" class="{{['tab', tab.c]}}" bindtap="{{tab.d}}">{{tab.a}}</view></view><view wx:if="{{e}}" class="loading-container"><uni-load-more wx:if="{{f}}" u-i="1147c60e-0" bind:__l="__l" u-p="{{f}}"/></view><view wx:else class="course-grid"><view wx:for="{{g}}" wx:for-item="cour" wx:key="f" class="card" bindtap="{{cour.g}}"><image src="{{cour.a}}" class="cover" mode="aspectFill" style="width:200px;height:200px"/><view class="content"><view class="title">{{cour.b}}</view><view class="desc">{{cour.c}}</view><view class="price-row"><text class="price">¥{{cour.d}}</text><text class="sales">已售 {{cour.e}}</text></view></view></view></view></view>

+ 173 - 0
unpackage/dist/dev/mp-weixin/pages/discover/index.wxss

@@ -0,0 +1,173 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+/* 颜色变量 */
+/* 行为相关颜色 */
+/* 文字基本颜色 */
+/* 背景颜色 */
+/* 边框颜色 */
+/* 尺寸变量 */
+/* 文字尺寸 */
+/* 图片尺寸 */
+/* Border Radius */
+/* 水平间距 */
+/* 垂直间距 */
+/* 透明度 */
+/* 文章场景相关 */
+.container {
+  min-height: 100vh;
+  background: linear-gradient(180deg, #eaf6ff 0%, #f7f8fa 100%);
+  padding-bottom: 120rpx;
+}
+.spacer {
+  height: 60rpx;
+  padding-top: 40px;
+}
+.search-bar {
+  display: flex;
+  align-items: center;
+  background: #fff;
+  border-radius: 40rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+  padding: 0 32rpx;
+  margin: 0 auto 24rpx auto;
+  width: 80vw;
+  max-width: 600rpx;
+  height: 80rpx;
+}
+input {
+  flex: 1;
+  border: none;
+  background: transparent;
+  font-size: 30rpx;
+  height: 80rpx;
+}
+.iconfont {
+  color: #bbb;
+  font-size: 36rpx;
+  margin-left: 10rpx;
+}
+.category-tabs {
+  display: flex;
+  margin: 20rpx 0 0 0;
+  background: #fff;
+  border-radius: 20rpx;
+  overflow-x: auto;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
+}
+.tab {
+  flex: 1;
+  text-align: center;
+  padding: 20rpx 0;
+  font-size: 30rpx;
+  color: #666;
+  position: relative;
+  white-space: nowrap;
+}
+.tab.active {
+  color: #3498db;
+  font-weight: bold;
+}
+.tab.active::after {
+  content: "";
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  transform: translateX(-50%);
+  width: 40rpx;
+  height: 6rpx;
+  background: #3498db;
+  border-radius: 3rpx;
+}
+.course-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 32rpx;
+  padding: 32rpx 24rpx 0 24rpx;
+}
+.card {
+  background: #fff;
+  border-radius: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+  overflow: hidden;
+  transition: transform 0.2s;
+  display: flex;
+  flex-direction: column;
+  min-height: 380rpx;
+}
+.card:active {
+  transform: scale(0.98);
+}
+.cover {
+  width: 100%;
+  height: 140rpx;
+  background-color: #f5f5f5;
+  border-radius: 20rpx 20rpx 0 0;
+}
+.content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  padding: 20rpx 16rpx 16rpx 16rpx;
+}
+.title {
+  font-size: 28rpx;
+  font-weight: 600;
+  margin-bottom: 8rpx;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.desc {
+  font-size: 24rpx;
+  color: #888;
+  margin-bottom: 12rpx;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+.price-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.price {
+  color: #e74c3c;
+  font-size: 28rpx;
+  font-weight: bold;
+}
+.sales {
+  font-size: 24rpx;
+  color: #999;
+}
+.loading-container,
+.error-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 40rpx;
+}
+.error-text {
+  color: #e74c3c;
+  font-size: 28rpx;
+  margin-bottom: 20rpx;
+}
+.retry-btn {
+  background: #3498db;
+  color: #fff;
+  padding: 16rpx 32rpx;
+  border-radius: 30rpx;
+  font-size: 28rpx;
+}

+ 37 - 0
unpackage/dist/dev/mp-weixin/pages/message/index.js

@@ -0,0 +1,37 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  data() {
+    return {
+      msgList: [
+        { title: "课程精选", icon: "/static/msg1.png", bg: "linear-gradient(135deg,#ffbcbc,#ffeded)", path: "/pages/message/selected" },
+        { title: "课程上新", icon: "/static/msg2.png", bg: "linear-gradient(135deg,#b6e3ff,#eaf7ff)", path: "" },
+        { title: "直播预约", icon: "/static/msg3.png", bg: "linear-gradient(135deg,#d6caff,#f3f0ff)", path: "" },
+        { title: "圈子消息", icon: "/static/msg4.png", bg: "linear-gradient(135deg,#b6ffe0,#eafff6)", path: "" }
+      ]
+    };
+  },
+  methods: {
+    goTo(item) {
+      if (item.path) {
+        common_vendor.index.navigateTo({ url: item.path });
+      }
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return {
+    a: common_vendor.f($data.msgList, (item, k0, i0) => {
+      return {
+        a: item.icon,
+        b: item.bg,
+        c: common_vendor.t(item.title),
+        d: item.title,
+        e: common_vendor.o(($event) => $options.goTo(item), item.title)
+      };
+    })
+  };
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/message/index.js.map

+ 5 - 0
unpackage/dist/dev/mp-weixin/pages/message/index.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "消息",
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/message/index.wxml

@@ -0,0 +1 @@
+<view class="msg-container"><view class="msg-header">消息</view><view class="msg-list"><view wx:for="{{a}}" wx:for-item="item" wx:key="d" class="msg-item" bindtap="{{item.e}}"><view class="msg-icon" style="{{'background:' + item.b}}"><image src="{{item.a}}" class="icon-img"/></view><view class="msg-info"><view class="msg-title">{{item.c}}</view><view class="msg-desc">暂无新消息</view></view></view></view></view>

+ 82 - 0
unpackage/dist/dev/mp-weixin/pages/message/index.wxss

@@ -0,0 +1,82 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+/* 颜色变量 */
+/* 行为相关颜色 */
+/* 文字基本颜色 */
+/* 背景颜色 */
+/* 边框颜色 */
+/* 尺寸变量 */
+/* 文字尺寸 */
+/* 图片尺寸 */
+/* Border Radius */
+/* 水平间距 */
+/* 垂直间距 */
+/* 透明度 */
+/* 文章场景相关 */
+.msg-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.msg-header {
+  text-align: center;
+  font-size: 40rpx;
+  font-weight: bold;
+  color: #222;
+  margin-top: 80rpx;
+  margin-bottom: 40rpx;
+  letter-spacing: 2rpx;
+}
+.msg-list {
+  margin: 0 0 0 0;
+}
+.msg-item {
+  display: flex;
+  align-items: center;
+  padding: 32rpx 40rpx 32rpx 40rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx 32rpx 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
+  transition: box-shadow 0.2s;
+}
+.msg-item:active {
+  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
+}
+.msg-icon {
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 32rpx;
+}
+.icon-img {
+  width: 48rpx;
+  height: 48rpx;
+}
+.msg-info {
+  display: flex;
+  flex-direction: column;
+}
+.msg-title {
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #222;
+  margin-bottom: 8rpx;
+}
+.msg-desc {
+  font-size: 24rpx;
+  color: #bbb;
+}

+ 9 - 0
unpackage/dist/dev/mp-weixin/pages/message/selected.js

@@ -0,0 +1,9 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {};
+function _sfc_render(_ctx, _cache) {
+  return {};
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/message/selected.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/message/selected.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "课程精选",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/message/selected.wxml

@@ -0,0 +1 @@
+<view class="simple-page">这里是课程精选详情</view>

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/message/selected.wxss

@@ -0,0 +1 @@
+.simple-page{padding:100rpx;text-align:center;color:#888;font-size:32rpx;}

+ 55 - 0
unpackage/dist/dev/mp-weixin/pages/mine/Merchant.js

@@ -0,0 +1,55 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const common_assets = require("../../common/assets.js");
+const _sfc_main = {
+  data() {
+    return {
+      hasShop: true
+      // 模拟有无店铺
+    };
+  },
+  onLoad() {
+  },
+  methods: {
+    jump() {
+      common_vendor.index.__f__("log", "at pages/mine/Merchant.vue:39", "123123");
+      common_vendor.wx$1.navigateToMiniProgram({
+        appId: "wx3d250e9c83ec74ee",
+        // 必填,未发布小程序的AppID(开发版/体验版均可)
+        path: "pages/index/index",
+        // 选填,如:'pages/index/index'
+        envVersion: "develop",
+        // 选填,指定跳转环境:develop(开发版)、trial(体验版)、release(正式版),未发布时用'develop'
+        success(res) {
+        },
+        fail(res) {
+        }
+      });
+    },
+    goToShopHome() {
+      common_vendor.index.switchTab({
+        url: "/pages/index/shopHome"
+      });
+    },
+    onKefu() {
+      common_vendor.index.showToast({ title: "客服功能待接入", icon: "none" });
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return common_vendor.e({
+    a: $data.hasShop
+  }, $data.hasShop ? {
+    b: common_assets._imports_0$4,
+    c: common_vendor.o(($event) => $options.jump())
+  } : {
+    d: common_assets._imports_1$1
+  }, {
+    e: common_vendor.o((...args) => $options.goToShopHome && $options.goToShopHome(...args)),
+    f: common_assets._imports_2,
+    g: common_vendor.o((...args) => $options.onKefu && $options.onKefu(...args))
+  });
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/mine/Merchant.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/mine/Merchant.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "商家后台管理",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/mine/Merchant.wxml

@@ -0,0 +1 @@
+<view class="main-content"><view class="title">请选择您的知识店铺</view><view wx:if="{{a}}" class="shop-card"><view class="shop-info" bindtap="{{c}}"><image class="shop-icon" src="{{b}}"/><view class="shop-name">知识店铺_WVV350567 <text class="shop-tag">试用版</text></view><view class="shop-status">最近访问</view></view><view class="shop-detail"><view>试用期至:2025-05-10(已过期)</view><view>访问身份:创建者</view></view></view><view wx:else class="no-shop"><image class="no-shop-img" src="{{d}}"/><view class="no-shop-text">暂无知识店铺,请创建</view></view><button class="create-btn" bindtap="{{e}}">创建知识店铺</button><view class="kefu-btn" bindtap="{{g}}"><image class="kefu-img" src="{{f}}"/><text>开店咨询</text></view></view>

+ 89 - 0
unpackage/dist/dev/mp-weixin/pages/mine/Merchant.wxss

@@ -0,0 +1,89 @@
+
+.main-content {
+		padding: 40rpx 30rpx 120rpx 30rpx;
+}
+.title {
+		font-size: 44rpx;
+		font-weight: bold;
+		margin-bottom: 40rpx;
+}
+.shop-card {
+		background: #f8fafd;
+		border-radius: 20rpx;
+		padding: 36rpx 30rpx;
+		margin-bottom: 40rpx;
+		box-shadow: 0 2rpx 8rpx #f0f1f2;
+}
+.shop-info {
+		display: flex;
+		align-items: center;
+		margin-bottom: 16rpx;
+}
+.shop-icon {
+		width: 60rpx;
+		height: 60rpx;
+		margin-right: 20rpx;
+}
+.shop-name {
+		font-size: 32rpx;
+		font-weight: 500;
+		margin-right: 16rpx;
+}
+.shop-tag {
+		font-size: 22rpx;
+		color: #fff;
+		background: #b3c6ff;
+		border-radius: 8rpx;
+		padding: 2rpx 10rpx;
+		margin-left: 8rpx;
+}
+.shop-status {
+		margin-left: auto;
+		color: #b3b3b3;
+		font-size: 26rpx;
+}
+.shop-detail {
+		color: #888;
+		font-size: 26rpx;
+}
+.no-shop {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		margin-bottom: 40rpx;
+}
+.no-shop-img {
+		width: 180rpx;
+		height: 180rpx;
+		margin-bottom: 20rpx;
+}
+.no-shop-text {
+		color: #b3b3b3;
+		font-size: 30rpx;
+}
+.create-btn {
+		width: 90%;
+		margin: 0 auto 40rpx auto;
+		background: #1880ff;
+		color: #fff;
+		font-size: 36rpx;
+		border-radius: 50rpx;
+		height: 90rpx;
+		line-height: 90rpx;
+}
+.kefu-btn {
+		position: fixed;
+		right: 40rpx;
+		bottom: 180rpx;
+		display: flex;
+		align-items: center;
+		background: #eaf3ff;
+		border-radius: 50rpx;
+		padding: 10rpx 30rpx;
+		box-shadow: 0 2rpx 8rpx #eaf3ff;
+}
+.kefu-img {
+		width: 60rpx;
+		height: 60rpx;
+		margin-right: 10rpx;
+}

+ 21 - 0
unpackage/dist/dev/mp-weixin/pages/mine/about.js

@@ -0,0 +1,21 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const common_assets = require("../../common/assets.js");
+const _sfc_main = {
+  methods: {
+    goWeb() {
+      common_vendor.index.setClipboardData({ data: "https://www.xiaoe-tech.com", success: () => {
+        common_vendor.index.showToast({ title: "官网地址已复制", icon: "none" });
+      } });
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return {
+    a: common_assets._imports_0$3,
+    b: common_vendor.o((...args) => $options.goWeb && $options.goWeb(...args))
+  };
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/mine/about.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/mine/about.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "了解小鹅通",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/mine/about.wxml

@@ -0,0 +1 @@
+<view class="about-container"><view class="about-title">了解小鹅通</view><view class="about-box"><image src="{{a}}" class="about-logo"/><view class="about-desc">小鹅通,专注知识付费与内容变现,助力每一位内容创作者。</view><view class="feature-list"><view class="feature-item">· 课程直播与录播</view><view class="feature-item">· 社群互动</view><view class="feature-item">· 多端分发</view><view class="feature-item">· 数据分析</view></view><button class="web-btn" bindtap="{{b}}">访问官网</button></view></view>

+ 76 - 0
unpackage/dist/dev/mp-weixin/pages/mine/about.wxss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+/* 颜色变量 */
+/* 行为相关颜色 */
+/* 文字基本颜色 */
+/* 背景颜色 */
+/* 边框颜色 */
+/* 尺寸变量 */
+/* 文字尺寸 */
+/* 图片尺寸 */
+/* Border Radius */
+/* 水平间距 */
+/* 垂直间距 */
+/* 透明度 */
+/* 文章场景相关 */
+.about-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+.about-title {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #222;
+  padding: 48rpx 0 32rpx 0;
+}
+.about-box {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 24rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 48rpx 24rpx 48rpx 24rpx;
+}
+.about-logo {
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 20rpx;
+  margin-bottom: 24rpx;
+}
+.about-desc {
+  font-size: 28rpx;
+  color: #555;
+  margin-bottom: 32rpx;
+  text-align: center;
+}
+.feature-list {
+  width: 100%;
+  margin-bottom: 32rpx;
+}
+.feature-item {
+  font-size: 26rpx;
+  color: #409EFF;
+  margin-bottom: 8rpx;
+  text-align: left;
+}
+.web-btn {
+  width: 80%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+}

+ 40 - 0
unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.js

@@ -0,0 +1,40 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  methods: {
+    submit() {
+      common_vendor.index.showModal({
+        title: "确认注销",
+        content: "注销后所有数据将无法恢复,是否继续?",
+        success: (res) => {
+          if (res.confirm) {
+            common_vendor.index.request({
+              url: "http://localhost:9527/api/cancelAccount",
+              method: "POST",
+              data: { uid: common_vendor.index.getStorageSync("uid") },
+              success: (res2) => {
+                if (res2.statusCode === 200 && res2.data.code === 200) {
+                  common_vendor.index.showToast({ title: "注销成功", icon: "success" });
+                  setTimeout(() => {
+                    common_vendor.index.clearStorageSync();
+                    common_vendor.index.reLaunch({ url: "/pages/index/index" });
+                  }, 1e3);
+                } else {
+                  common_vendor.index.showToast({ title: res2.data.message || "注销失败", icon: "none" });
+                }
+              }
+            });
+          }
+        }
+      });
+    }
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return {
+    a: common_vendor.o((...args) => $options.submit && $options.submit(...args))
+  };
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-4c3b2932"]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/mine/cancelAccount.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "账号注销",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.wxml

@@ -0,0 +1 @@
+<view class="cancel-account-container data-v-4c3b2932"><view class="header data-v-4c3b2932">账号注销</view><view class="desc data-v-4c3b2932">注销账号将清空所有个人数据且无法恢复,是否确认注销?</view><button class="submit-btn data-v-4c3b2932" type="warn" bindtap="{{a}}">确认注销</button></view>

+ 34 - 0
unpackage/dist/dev/mp-weixin/pages/mine/cancelAccount.wxss

@@ -0,0 +1,34 @@
+
+.cancel-account-container.data-v-4c3b2932 {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.header.data-v-4c3b2932 {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+  width: 100%;
+}
+.desc.data-v-4c3b2932 {
+  font-size: 28rpx;
+  color: #e74c3c;
+  margin: 60rpx 0 40rpx 0;
+  text-align: center;
+  padding: 0 32rpx;
+}
+.submit-btn.data-v-4c3b2932 {
+  width: 80%;
+  background: #e74c3c;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}

+ 78 - 0
unpackage/dist/dev/mp-weixin/pages/mine/changePhone.js

@@ -0,0 +1,78 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  data() {
+    return {
+      newPhone: "",
+      code: "",
+      countdown: 0,
+      timer: null
+    };
+  },
+  methods: {
+    sendCode() {
+      if (!/^1[3-9]\d{9}$/.test(this.newPhone)) {
+        common_vendor.index.showToast({ title: "请输入正确手机号", icon: "none" });
+        return;
+      }
+      common_vendor.index.request({
+        url: "http://localhost:9527/api/sendCode",
+        method: "POST",
+        data: { phone: this.newPhone }
+      });
+      common_vendor.index.showToast({ title: "验证码已发送", icon: "success" });
+      this.countdown = 60;
+      this.timer = setInterval(() => {
+        this.countdown--;
+        if (this.countdown <= 0)
+          clearInterval(this.timer);
+      }, 1e3);
+    },
+    submit() {
+      if (!/^1[3-9]\d{9}$/.test(this.newPhone)) {
+        common_vendor.index.showToast({ title: "请输入正确手机号", icon: "none" });
+        return;
+      }
+      if (!/^\d{6}$/.test(this.code)) {
+        common_vendor.index.showToast({ title: "请输入6位验证码", icon: "none" });
+        return;
+      }
+      common_vendor.index.request({
+        url: "http://localhost:9527/api/updatePhone",
+        method: "POST",
+        data: {
+          uid: common_vendor.index.getStorageSync("uid"),
+          phone: this.newPhone,
+          code: this.code
+        },
+        success: (res) => {
+          if (res.statusCode === 200 && res.data.code === 200) {
+            common_vendor.index.showToast({ title: "更换成功", icon: "success" });
+            setTimeout(() => common_vendor.index.navigateBack(), 1e3);
+          } else {
+            common_vendor.index.showToast({ title: res.data.message || "更换失败", icon: "none" });
+          }
+        }
+      });
+    }
+  },
+  onUnload() {
+    if (this.timer)
+      clearInterval(this.timer);
+  }
+};
+function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
+  return {
+    a: $data.newPhone,
+    b: common_vendor.o(($event) => $data.newPhone = $event.detail.value),
+    c: $data.code,
+    d: common_vendor.o(($event) => $data.code = $event.detail.value),
+    e: common_vendor.t($data.countdown > 0 ? $data.countdown + "s" : "获取验证码"),
+    f: $data.countdown > 0,
+    g: common_vendor.o((...args) => $options.sendCode && $options.sendCode(...args)),
+    h: common_vendor.o((...args) => $options.submit && $options.submit(...args))
+  };
+}
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-a44ae884"]]);
+wx.createPage(MiniProgramPage);
+//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/mine/changePhone.js.map

+ 4 - 0
unpackage/dist/dev/mp-weixin/pages/mine/changePhone.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "更换手机号",
+  "usingComponents": {}
+}

+ 1 - 0
unpackage/dist/dev/mp-weixin/pages/mine/changePhone.wxml

@@ -0,0 +1 @@
+<view class="change-phone-container data-v-a44ae884"><view class="header data-v-a44ae884">更换手机号</view><view class="form data-v-a44ae884"><input type="number" maxlength="11" placeholder="请输入新手机号" class="input data-v-a44ae884" value="{{a}}" bindinput="{{b}}"/><view class="code-row data-v-a44ae884"><input maxlength="6" placeholder="请输入验证码" class="input code-input data-v-a44ae884" value="{{c}}" bindinput="{{d}}"/><button class="code-btn data-v-a44ae884" disabled="{{f}}" bindtap="{{g}}">{{e}}</button></view><button class="submit-btn data-v-a44ae884" bindtap="{{h}}">确认更换</button></view></view>

+ 58 - 0
unpackage/dist/dev/mp-weixin/pages/mine/changePhone.wxss

@@ -0,0 +1,58 @@
+
+.change-phone-container.data-v-a44ae884 {
+  min-height: 100vh;
+  background: #f7f8fa;
+  padding: 40rpx 0;
+}
+.header.data-v-a44ae884 {
+  text-align: center;
+  font-size: 36rpx;
+  font-weight: bold;
+  margin-bottom: 40rpx;
+  background: #fff;
+  padding: 32rpx 0;
+}
+.form.data-v-a44ae884 {
+  background: #fff;
+  border-radius: 20rpx;
+  margin: 0 32rpx;
+  padding: 40rpx 32rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+  display: flex;
+  flex-direction: column;
+  gap: 32rpx;
+}
+.input.data-v-a44ae884 {
+  width: 100%;
+  height: 80rpx;
+  border: 1rpx solid #eee;
+  border-radius: 12rpx;
+  padding: 0 24rpx;
+  font-size: 30rpx;
+  background: #f7f8fa;
+}
+.code-row.data-v-a44ae884 {
+  display: flex;
+  gap: 16rpx;
+}
+.code-input.data-v-a44ae884 {
+  flex: 1;
+}
+.code-btn.data-v-a44ae884 {
+  width: 180rpx;
+  height: 80rpx;
+  background: #409EFF;
+  color: #fff;
+  border: none;
+  border-radius: 12rpx;
+  font-size: 28rpx;
+}
+.submit-btn.data-v-a44ae884 {
+  width: 100%;
+  background: #409EFF;
+  color: #fff;
+  border-radius: 12rpx;
+  font-size: 32rpx;
+  margin-top: 16rpx;
+  height: 80rpx;
+}

Some files were not shown because too many files changed in this diff