yonge 4 дней назад
Сommit
53ed19eaed

+ 31 - 0
.gitignore

@@ -0,0 +1,31 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+# dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
+.DS_Store

+ 5 - 0
app.js

@@ -0,0 +1,5 @@
+App({
+  onLaunch: function () {
+
+  }
+})

+ 17 - 0
app.json

@@ -0,0 +1,17 @@
+{
+  "pages": [
+    "pages/product/index",
+    "pages/trial/index",
+    "pages/index/index"
+  ],
+  "window": {
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#667eea",
+    "navigationBarTitleText": "酷乐秀助手",
+    "navigationBarTextStyle": "white",
+    "backgroundColor": "#f8f9fa",
+    "enablePullDownRefresh": false
+  },
+  "style": "v2",
+  "sitemapLocation": "sitemap.json"
+}

+ 32 - 0
app.ttss

@@ -0,0 +1,32 @@
+.page-tabbar {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  height: 96rpx;
+  background: #ffffff;
+  border-top: 1rpx solid #e8e8e8;
+  display: flex;
+  z-index: 200;
+}
+
+.page-tab-item {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.page-tab-text {
+  font-size: 26rpx;
+  color: #7a8799;
+  font-weight: 500;
+}
+
+.page-tab-item-active {
+  background: #f8fbff;
+}
+
+.page-tab-text-active {
+  color: #4facfe;
+}


BIN
images/icon_music.png


+ 519 - 0
pages/index/index.js

@@ -0,0 +1,519 @@
+const _app = getApp()
+
+// 办公助手服务配置
+const ServiceConfig = {
+  // 样例API地址,请替换为您的真实服务地址
+  apiUrl: 'https://kt.colexiu.com/edu-app/open/coze/agent',
+  // 请求超时时间(毫秒)
+  timeout: 60000,
+  // 请求头配置
+  headers: {
+    'Content-Type': 'application/json'
+  }
+}
+
+// 用户信息管理
+const UserManager = {
+  // 获取用户唯一标识
+  getUserIdentifier: function () {
+    return new Promise((resolve, _reject) => {
+      // 尝试从缓存获取用户ID
+      const cachedUserId = tt.getStorageSync('user_id')
+      if (cachedUserId) {
+        resolve(cachedUserId)
+        return
+      }
+      
+      // 调用登录API获取用户标识
+      tt.login({
+        force: false, // 不强制调起登录框
+        success: function (res) {
+          console.log('登录成功:', res)
+          
+          if (res.isLogin && res.code) {
+            // 已登录用户,使用code作为临时标识
+            // 实际应用中,应该将code发送到服务端换取openid
+            const userId = 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
+            
+            // 缓存用户ID
+            tt.setStorageSync('user_id', userId)
+            resolve(userId)
+          } else if (res.anonymousCode) {
+            // 匿名用户,使用anonymousCode作为标识
+            const anonymousUserId = 'anonymous_' + res.anonymousCode.substr(0, 16)
+            
+            // 缓存匿名用户ID
+            tt.setStorageSync('user_id', anonymousUserId)
+            resolve(anonymousUserId)
+          } else {
+            // 生成默认用户ID
+            const defaultUserId = 'default_' + Date.now()
+            tt.setStorageSync('user_id', defaultUserId)
+            resolve(defaultUserId)
+          }
+        },
+        fail: function (err) {
+          console.error('登录失败:', err)
+          // 生成默认用户ID作为备选
+          const defaultUserId = 'default_' + Date.now()
+          tt.setStorageSync('user_id', defaultUserId)
+          resolve(defaultUserId)
+        }
+      })
+    })
+  },
+  
+  // 清除用户信息
+  clearUserInfo: function () {
+    tt.removeStorageSync('user_id')
+  }
+}
+
+Page({
+  data: {
+    appName: '酷乐秀',
+    version: '1.0.0',
+    messageContent: '',
+    showReply: false,
+    replyContent: '',
+    isLoading: false,
+    apiError: false,
+    currentUserId: '',
+    chatMessages: [], // 聊天消息列表(按时间顺序)
+    scrollTop: 0, // 滚动位置
+    scrollIntoView: '' // 滚动锚点
+  },
+  
+  onLoad: function () {
+    console.log('办公效率助手小程序已加载')
+    this.setData({
+      appName: '酷乐秀',
+      version: '1.0.0'
+    })
+
+    // 初始化用户标识
+    this.initUserIdentifier()
+  },
+  
+  // 初始化用户标识
+  initUserIdentifier: function () {
+    const that = this
+    UserManager.getUserIdentifier()
+      .then(userId => {
+        console.log('获取到用户ID:', userId)
+        that.setData({
+          currentUserId: userId
+        })
+      })
+      .catch(err => {
+        console.error('获取用户ID失败:', err)
+        // 生成默认用户ID
+        const defaultUserId = 'default_' + Date.now()
+        that.setData({
+          currentUserId: defaultUserId
+        })
+        tt.setStorageSync('user_id', defaultUserId)
+      })
+  },
+  
+  onShow: function () {
+    console.log('办公效率助手小程序页面显示')
+  },
+  
+  // 页面初次渲染完成
+  onReady: function () {
+    console.log('页面初次渲染完成')
+    // 可以在这里添加需要在页面渲染完成后执行的逻辑
+  },
+  
+  // 点击发送消息按钮(兼容两种方法名)
+  handleSendMessage: function () {
+    this.handleSendPrivateMessage()
+  },
+  
+  // 点击发送消息按钮
+  handleSendPrivateMessage: function () {
+    const content = this.data.messageContent.trim()
+    
+    if (!content) {
+      tt.showToast({
+        title: '请输入消息内容',
+        icon: 'none',
+        duration: 2000
+      })
+      return
+    }
+    
+    // 将用户消息添加到聊天记录
+    const userMessage = {
+      type: 'user',
+      content: content,
+      time: this.getCurrentTime(),
+      timestamp: Date.now()
+    }
+    
+    this.setData({
+      chatMessages: [...this.data.chatMessages, userMessage],
+      isLoading: true,
+      apiError: false,
+      messageContent: ''
+    }, () => {
+      // 滚动到底部
+      this.scrollToBottom()
+    })
+    
+    // 调用助手服务
+    this.callReplyService(content)
+  },
+  
+  // 调用助手服务
+  callReplyService: function (userMessage) {
+    const that = this
+    
+    // 获取用户ID并调用服务
+    UserManager.getUserIdentifier()
+      .then(userId => {
+        console.log('调用助手服务,用户ID:', userId)
+        
+        // 更新当前用户ID
+        that.setData({
+          currentUserId: userId
+        })
+        
+        // 发起服务请求
+        tt.request({
+          url: ServiceConfig.apiUrl,
+          method: 'POST',
+          data: {
+            message: userMessage,
+            userId: userId, // 添加用户ID参数
+            appId: 'yyszkt_help',
+            timestamp: Date.now(),
+            // 可以根据需要添加更多参数
+            context: 'music_assistant', // 保持接口参数不变
+            language: 'zh-CN',
+            userType: userId.startsWith('anonymous_') ? 'anonymous' : 'registered'
+          },
+          header: ServiceConfig.headers,
+          timeout: ServiceConfig.timeout,
+          success: function (res) {
+            console.log('服务调用成功:', res)
+            
+            // 处理助手回复
+            let assistantReply = ''
+            
+            if (res.statusCode === 200 && res.data) {
+              // 根据API响应格式处理回复
+              if (typeof res.data === 'string') {
+                assistantReply = res.data
+              } else if (res.data.reply) {
+                assistantReply = res.data.reply
+              } else if (res.data.choices && res.data.choices[0] && res.data.choices[0].message) {
+                assistantReply = res.data.choices[0].message.content
+              } else {
+                assistantReply = '已收到您的消息,我这边正在为您整理建议。'
+              }
+            } else {
+              // API调用失败,使用备用回复
+              assistantReply = that.generateFallbackResponse(userMessage)
+            }
+            
+            // 将助手回复添加到聊天记录
+            const assistantReplyMessage = {
+              type: 'assistant',
+              content: assistantReply,
+              time: that.getCurrentTime(),
+              timestamp: Date.now()
+            }
+            
+            that.setData({
+              chatMessages: [...that.data.chatMessages, assistantReplyMessage],
+              replyContent: assistantReply,
+              showReply: true,
+              isLoading: false
+            }, () => {
+              // 滚动到底部
+              that.scrollToBottom()
+            })
+            
+            // 清空输入框
+            that.setData({
+              messageContent: ''
+            })
+          },
+          fail: function (err) {
+            console.error('服务调用失败:', err)
+            
+            // 显示错误提示
+            tt.showToast({
+              title: '网络异常,使用本地建议',
+              icon: 'none',
+              duration: 2000
+            })
+            
+            // 使用本地备用建议
+            const fallbackReply = that.generateFallbackResponse(userMessage)
+            
+            that.setData({
+              replyContent: fallbackReply,
+              showReply: true,
+              isLoading: false,
+              apiError: true
+            })
+            
+            // 清空输入框
+            that.setData({
+              messageContent: ''
+            })
+          },
+          complete: function () {
+            console.log('服务调用完成')
+          }
+        })
+      })
+      .catch(err => {
+        console.error('获取用户ID失败:', err)
+        
+        // 使用默认用户ID继续调用
+        const defaultUserId = 'default_' + Date.now()
+        that.callReplyServiceWithUserId(userMessage, defaultUserId)
+      })
+  },
+  
+  // 使用指定用户ID调用服务
+  callReplyServiceWithUserId: function (userMessage, userId) {
+    const that = this
+    
+    tt.request({
+      url: ServiceConfig.apiUrl,
+      method: 'POST',
+      data: {
+        message: userMessage,
+        userId: userId,
+        appId: 'yyszkt_help',
+        timestamp: Date.now(),
+        context: 'music_assistant',
+        language: 'zh-CN',
+        userType: userId.startsWith('anonymous_') ? 'anonymous' : 'registered'
+      },
+      header: ServiceConfig.headers,
+      timeout: ServiceConfig.timeout,
+      success: function (res) {
+        // 成功处理逻辑...
+        let assistantReply = ''
+        
+        if (res.statusCode === 200 && res.data) {
+          if (typeof res.data === 'string') {
+            assistantReply = res.data
+          } else if (res.data.reply) {
+            assistantReply = res.data.reply
+          } else if (res.data.choices && res.data.choices[0] && res.data.choices[0].message) {
+            assistantReply = res.data.choices[0].message.content
+          } else {
+            assistantReply = '已收到您的消息,我这边正在为您整理建议。'
+          }
+        } else {
+          assistantReply = that.generateFallbackResponse(userMessage)
+        }
+        
+        // 将助手回复添加到聊天记录
+        const assistantReplyMessage = {
+          type: 'assistant',
+          content: assistantReply,
+          time: that.getCurrentTime(),
+          timestamp: Date.now()
+        }
+        
+        that.setData({
+          chatMessages: [...that.data.chatMessages, assistantReplyMessage],
+          replyContent: assistantReply,
+          showReply: true,
+          isLoading: false
+        }, () => {
+          // 滚动到底部
+          that.scrollToBottom()
+        })
+        
+        that.setData({
+          messageContent: ''
+        })
+      },
+      fail: function (err) {
+        console.error('服务调用失败:', err)
+        
+        tt.showToast({
+          title: '网络异常,使用本地建议',
+          icon: 'none',
+          duration: 2000
+        })
+        
+        const fallbackReply = that.generateFallbackResponse(userMessage)
+        
+        // 将助手回复添加到聊天记录
+        const assistantReplyMessage = {
+          type: 'assistant',
+          content: fallbackReply,
+          time: that.getCurrentTime(),
+          timestamp: Date.now()
+        }
+        
+        that.setData({
+          chatMessages: [...that.data.chatMessages, assistantReplyMessage],
+          replyContent: fallbackReply,
+          showReply: true,
+          isLoading: false,
+          apiError: true
+        }, () => {
+          // 滚动到底部
+          that.scrollToBottom()
+        })
+        
+        that.setData({
+          messageContent: ''
+        })
+      },
+      complete: function () {
+      }
+    })
+  },
+  
+  // 生成备用回复(当API调用失败时使用)
+  generateFallbackResponse: function (userMessage) {
+    return this.generateReplyResponse(userMessage)
+  },
+  
+  // 生成助手回复内容(本地备用)
+  generateReplyResponse: function (userMessage) {
+    
+    return '当前客服不在线,暂无法回复消息,请稍等。'
+  },
+  
+  // 关闭助手回复区域
+  handleCloseReply: function () {
+    this.setData({
+      showReply: false,
+      replyContent: '',
+      apiError: false
+    })
+  },
+  
+  // 重新获取用户ID(用于调试或重置)
+  refreshUserIdentifier: function () {
+    const that = this
+    UserManager.clearUserInfo()
+    
+    tt.showLoading({
+      title: '重新获取用户信息...',
+      mask: true
+    })
+    
+    UserManager.getUserIdentifier()
+      .then(userId => {
+        tt.hideLoading()
+        that.setData({
+          currentUserId: userId
+        })
+        tt.showToast({
+          title: '用户信息更新成功',
+          icon: 'success',
+          duration: 2000
+        })
+      })
+      .catch(_err => {
+        tt.hideLoading()
+        tt.showToast({
+          title: '用户信息更新失败',
+          icon: 'none',
+          duration: 2000
+        })
+      })
+  },
+  
+  // 输入框内容变化
+  handleInputChange: function (e) {
+    this.setData({
+      messageContent: e.detail.value
+    })
+  },
+
+  // 跳转产品介绍
+  handleGoProduct: function () {
+    tt.redirectTo({
+      url: '/pages/product/index'
+    })
+  },
+
+  // 跳转申请试用
+  handleGoTrial: function () {
+    tt.redirectTo({
+      url: '/pages/trial/index'
+    })
+  },
+  
+  // 获取当前时间
+  getCurrentTime: function () {
+    const now = new Date()
+    const hours = now.getHours().toString().padStart(2, '0')
+    const minutes = now.getMinutes().toString().padStart(2, '0')
+    return `${hours}:${minutes}`
+  },
+  
+  // 滚动到底部 - 完全重写的专业级实现
+  scrollToBottom: function () {
+    this.setData({
+      scrollIntoView: ''
+    })
+
+    setTimeout(() => {
+      this.setData({
+        scrollIntoView: 'bottom-anchor'
+      })
+    }, 20)
+
+    setTimeout(() => {
+      this.setData({
+        scrollTop: this.data.scrollTop + 9999
+      })
+    }, 120)
+
+    setTimeout(() => {
+      this.ensureLastMessageInView(0)
+    }, 180)
+  },
+
+  // 确保最后一条消息完整显示在消息区可视范围内
+  ensureLastMessageInView: function (retryCount) {
+    const MAX_RETRY = 5
+    if (retryCount >= MAX_RETRY) {
+      return
+    }
+
+    const query = tt.createSelectorQuery()
+    query.selectAll('.message-item').boundingClientRect()
+    query.select('.chat-container').boundingClientRect()
+    query.exec((res) => {
+      const messageRects = res[0]
+      const chatRect = res[1]
+
+      if (!messageRects || !messageRects.length || !chatRect) {
+        return
+      }
+
+      const lastMessageRect = messageRects[messageRects.length - 1]
+      const safeBottom = chatRect.bottom - 16
+      const overlapHeight = lastMessageRect.bottom - safeBottom
+
+      if (overlapHeight > 0) {
+        this.setData({
+          scrollIntoView: '',
+          scrollTop: this.data.scrollTop + overlapHeight + 24
+        })
+
+        setTimeout(() => {
+          this.ensureLastMessageInView(retryCount + 1)
+        }, 60)
+      }
+    })
+  },
+
+})

+ 4 - 0
pages/index/index.json

@@ -0,0 +1,4 @@
+{
+  "usingComponents": {},
+  "navigationBarTitleText": "联系客服"
+}

+ 74 - 0
pages/index/index.ttml

@@ -0,0 +1,74 @@
+<view class="container">
+  
+  <!-- 导航栏下方简介 -->
+  <view class="nav-intro-section">
+    <text class="nav-intro-text">本小程序提供酷乐秀公司旗下软件的咨询、问题反馈和收集用户建议</text>
+  </view>
+
+  <!-- 聊天消息区域 -->
+  <scroll-view class="chat-container" scroll-y="true" scroll-top="{{scrollTop}}" scroll-into-view="{{scrollIntoView}}" scroll-with-animation="true">
+    <!-- 聊天消息列表(按时间顺序) -->
+    <view tt:for="{{chatMessages}}" tt:key="timestamp">
+      <!-- 助手消息 -->
+      <view class="message-item message-left" tt:if="{{item.type === 'assistant'}}">
+        <view class="avatar">助</view>
+        <view class="message-content">
+          <text class="message-text">{{item.content}}</text>
+          <text class="message-time">{{item.time}}</text>
+        </view>
+      </view>
+      
+      <!-- 用户消息 -->
+      <view class="message-item message-right" tt:elif="{{item.type === 'user'}}">
+        <view class="message-content">
+          <text class="message-text">{{item.content}}</text>
+          <text class="message-time">{{item.time}}</text>
+        </view>
+        <view class="avatar user-avatar">我</view>
+      </view>
+    </view>
+
+    <!-- 滚动锚点 -->
+    <view id="bottom-anchor"></view>
+  </scroll-view>
+
+
+  <!-- 底部区域:输入区 -->
+  <view class="bottom-section">
+    <!-- 输入区域 -->
+    <view class="input-container">
+      <view class="input-wrapper">
+        <textarea 
+          class="message-input" 
+          placeholder="请输入消息内容..." 
+          bindinput="handleInputChange" 
+          value="{{messageContent}}" 
+          maxlength="500"
+          adjust-position="false"
+          cursor-spacing="20"
+        ></textarea>
+        <text class="char-count-inside">{{messageContent.length}}/500</text>
+        <view class="input-actions">
+          <button 
+            class="send-btn {{messageContent ? 'active' : ''}}" 
+            bindtap="handleSendMessage"
+            disabled="{{!messageContent}}"
+          >
+            <text class="send-icon">➤</text>
+          </button>
+        </view>
+      </view>
+    </view>
+  </view>
+
+  <!-- 聊天页固定菜单 -->
+  <view class="page-tabbar">
+    <view class="page-tab-item" bindtap="handleGoProduct">
+      <text class="page-tab-text">产品介绍</text>
+    </view>
+    <view class="page-tab-item" bindtap="handleGoTrial">
+      <text class="page-tab-text">申请试用</text>
+    </view>
+  </view>
+
+</view>

+ 691 - 0
pages/index/index.ttss

@@ -0,0 +1,691 @@
+/* 页面容器 - 符合抖音小程序视觉规范 */
+.container {
+  min-height: 100vh;
+  height: 100vh;
+  background: #f8f9fa;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  padding-bottom: 100rpx;
+}
+
+/* 顶部导航栏 */
+.nav-bar {
+  height: 88rpx;
+  background: #ffffff;
+  border-bottom: 1rpx solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 32rpx;
+  flex-shrink: 0;
+}
+
+.nav-left {
+  display: flex;
+  align-items: center;
+}
+
+.nav-logo {
+  width: 48rpx;
+  height: 48rpx;
+  border-radius: 8rpx;
+  margin-right: 16rpx;
+}
+
+.nav-title {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #1a1a1a;
+  line-height: 1.2;
+}
+
+.nav-right {
+  display: flex;
+  align-items: center;
+}
+
+.nav-icon {
+  font-size: 36rpx;
+  color: #666666;
+  padding: 8rpx;
+}
+
+/* 聊天消息区域 - 完全重写的滚动解决方案 */
+.chat-container {
+  flex: 1;
+  min-height: 0;
+  background: #f8f9fa;
+  padding: 24rpx 40rpx 40rpx 40rpx;
+  overflow-y: auto;
+  box-sizing: border-box;
+  height: auto;
+  -webkit-overflow-scrolling: touch; /* 添加iOS滚动惯性 */
+  position: relative;
+}
+
+/* 消息项通用样式 */
+.message-item {
+  display: flex;
+  width: 100%;
+  box-sizing: border-box;
+  padding: 0;
+  margin-bottom: 32rpx;
+  animation: fadeIn 0.3s ease-out;
+}
+
+.message-left {
+  justify-content: flex-start;
+}
+
+.message-right {
+  justify-content: flex-end;
+  padding-right: 0;
+}
+
+.message-center {
+  justify-content: center;
+}
+
+/* 头像样式 - 彻底解决显示不全和边框遮挡问题 */
+.avatar {
+  width: 60rpx; /* 稍微减小宽度,为边框留出更多空间 */
+  height: 60rpx; /* 稍微减小高度,保持比例 */
+  border-radius: 50%;
+  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 30rpx; /* 相应调整字体大小 */
+  color: #ffffff;
+  flex-shrink: 0;
+  margin: 0;
+  z-index: 1; /* 避免头像压到固定输入区上层 */
+  position: relative;
+  overflow: hidden; /* 确保头像内容在容器内完整显示 */
+  line-height: 60rpx; /* 让头像文字垂直居中完整显示 */
+  min-width: 60rpx; /* 固定最小宽度 */
+  min-height: 60rpx; /* 固定最小高度 */
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); /* 添加阴影增强可见性 */
+}
+
+.user-avatar {
+  background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
+  order: 2;
+}
+
+.message-left .avatar {
+  margin-right: 12rpx;
+}
+
+.message-right .avatar {
+  margin-left: 12rpx;
+}
+
+/* 消息内容区域 */
+.message-content {
+  max-width: 440rpx;
+  background: #ffffff;
+  border-radius: 16rpx;
+  padding: 20rpx 24rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+  position: relative;
+}
+
+.message-right .message-content {
+  background: #4facfe;
+}
+
+.message-right .message-content::before {
+  content: '';
+  position: absolute;
+  right: -8rpx;
+  top: 20rpx;
+  width: 0;
+  height: 0;
+  border-left: 8rpx solid #4facfe;
+  border-top: 8rpx solid transparent;
+  border-bottom: 8rpx solid transparent;
+}
+
+.message-left .message-content::before {
+  content: '';
+  position: absolute;
+  left: -8rpx;
+  top: 20rpx;
+  width: 0;
+  height: 0;
+  border-right: 8rpx solid #ffffff;
+  border-top: 8rpx solid transparent;
+  border-bottom: 8rpx solid transparent;
+}
+
+/* 消息文本 */
+.message-text {
+  font-size: 28rpx;
+  color: #1a1a1a;
+  line-height: 1.5;
+  word-break: break-word;
+  /* 与输入框保持完全一致的字体渲染 */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.message-right .message-text {
+  color: #ffffff;
+}
+
+/* 消息时间 */
+.message-time {
+  font-size: 20rpx;
+  color: #999999;
+  margin-top: 8rpx;
+  display: block;
+}
+
+.message-right .message-time {
+  color: rgba(255, 255, 255, 0.8);
+  text-align: right;
+}
+
+/* 提示消息 */
+.tip-content {
+  background: rgba(255, 255, 255, 0.8);
+  border-radius: 20rpx;
+  padding: 12rpx 24rpx;
+  backdrop-filter: blur(10rpx);
+}
+
+.tip-text {
+  font-size: 24rpx;
+  color: #666666;
+  font-style: italic;
+}
+
+/* 底部区域:输入区 + 版权信息 */
+.bottom-section {
+  flex-shrink: 0;
+  background: #ffffff;
+  border-top: 1rpx solid #e8e8e8;
+}
+
+/* 输入区域 */
+.input-container {
+  background: #ffffff;
+  padding: 20rpx 32rpx;
+  position: relative;
+  box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
+}
+
+.input-wrapper {
+  background: #f8f9fa;
+  border-radius: 24rpx;
+  border: 1rpx solid #e8e8e8;
+  position: relative;
+  padding: 0;
+}
+
+.message-input {
+  width: 100%;
+  min-height: 120rpx;
+  max-height: 200rpx;
+  background: transparent;
+  border: none;
+  font-size: 28rpx; /* 与消息记录完全一致 */
+  color: #1a1a1a; /* 与助手消息文本颜色完全一致 */
+  line-height: 1.6; /* 优化行高 */
+  padding: 16rpx 120rpx 40rpx 16rpx;
+  resize: none;
+  box-sizing: border-box;
+  font-weight: 400; /* 确保字体权重一致 */
+  /* 针对 textarea 原生组件的特殊优化 */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.message-input::placeholder {
+  color: #999999;
+  font-size: 28rpx;
+}
+
+/* 输入框内部元素 */
+.char-count-inside {
+  position: absolute;
+  bottom: 8rpx;
+  right: 100rpx;
+  font-size: 20rpx;
+  color: #999999;
+  z-index: 10;
+}
+
+.input-actions {
+  position: absolute;
+  bottom: 8rpx;
+  right: 16rpx;
+  display: flex;
+  align-items: center;
+  flex-shrink: 0;
+}
+
+.send-btn {
+  width: 60rpx;
+  height: 60rpx;
+  border-radius: 50%;
+  background: #e8e8e8;
+  border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.3s ease;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.send-btn.active {
+  background: #4facfe;
+  box-shadow: 0 2rpx 12rpx rgba(79, 172, 254, 0.4);
+}
+
+.send-btn::after {
+  border: none;
+}
+
+.send-icon {
+  font-size: 28rpx;
+  color: #ffffff;
+  transform: rotate(225deg);
+  display: block;
+}
+
+.send-btn:not(.active) .send-icon {
+  color: #999999;
+}
+
+.send-btn:not(.active) {
+  background: #e8e8e8;
+}
+
+.send-btn:active {
+  transform: scale(0.95);
+}
+
+/* 加载状态 */
+.loading-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.loading-content {
+  background: #ffffff;
+  border-radius: 16rpx;
+  padding: 32rpx;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+}
+
+.loading-dots {
+  display: flex;
+  gap: 8rpx;
+  margin-bottom: 16rpx;
+}
+
+.dot {
+  width: 12rpx;
+  height: 12rpx;
+  border-radius: 50%;
+  background: #4facfe;
+  animation: bounce 1.4s infinite ease-in-out;
+}
+
+.dot:nth-child(1) {
+  animation-delay: -0.32s;
+}
+
+.dot:nth-child(2) {
+  animation-delay: -0.16s;
+}
+
+.loading-text {
+  font-size: 24rpx;
+  color: #666666;
+}
+
+/* 动画效果 */
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(20rpx);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes bounce {
+  0%, 80%, 100% {
+    transform: scale(0.8);
+    opacity: 0.5;
+  }
+  40% {
+    transform: scale(1);
+    opacity: 1;
+  }
+}
+
+/* 滚动锚点 */
+#bottom-anchor {
+  height: 120rpx; /* 给最新消息预留可视缓冲,避免贴到底部输入区边缘 */
+}
+
+/* 导航栏下方简介区域 */
+.nav-intro-section {
+  background: rgba(255, 255, 255, 0.95);
+  border-bottom: 1rpx solid #e8e8e8;
+  padding: 16rpx 32rpx;
+  text-align: center;
+  flex-shrink: 0;
+}
+
+.nav-intro-text {
+  font-size: 24rpx;
+  color: #666666;
+  line-height: 1.4;
+  display: block;
+}
+
+/* 底部版权信息 */
+.footer-section {
+  background: #ffffff;
+  border-top: 1rpx solid #e8e8e8;
+  padding: 16rpx 32rpx;
+  text-align: center;
+  position: relative;
+}
+
+/* 顶部标题区域 */
+.header {
+  text-align: center;
+  margin-bottom: 0;
+  padding: 20rpx 0 16rpx;
+  flex-shrink: 0;
+}
+
+.logo-section {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 8rpx;
+}
+
+.logo {
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 16rpx;
+  margin-right: 12rpx;
+}
+
+.app-name {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #ffffff;
+  text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
+  line-height: 1.2;
+}
+
+.welcome-text {
+  font-size: 20rpx;
+  color: rgba(255, 255, 255, 0.85);
+  line-height: 1.3;
+  max-width: 400rpx;
+  margin: 0 auto;
+  padding: 0 16rpx;
+}
+
+/* 功能介绍区域 */
+.feature-section {
+  margin-bottom: 16rpx;
+  flex-shrink: 0;
+}
+
+.feature-item {
+  background: rgba(255, 255, 255, 0.98);
+  border-radius: 16rpx;
+  padding: 16rpx;
+  margin-bottom: 8rpx;
+  display: flex;
+  align-items: center;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+  transition: all 0.3s ease;
+}
+
+.feature-item:active {
+  transform: scale(0.98);
+}
+
+.feature-icon {
+  font-size: 32rpx;
+  margin-right: 16rpx;
+  width: 40rpx;
+  text-align: center;
+  flex-shrink: 0;
+}
+
+.feature-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.feature-title {
+  font-size: 22rpx;
+  font-weight: 600;
+  color: #2c3e50;
+  display: block;
+  margin-bottom: 4rpx;
+  line-height: 1.2;
+}
+
+.feature-desc {
+  font-size: 18rpx;
+  color: #7f8c8d;
+  line-height: 1.3;
+  display: block;
+}
+
+/* 操作按钮区域 */
+.action-section {
+  display: flex;
+  flex-direction: column;
+  gap: 8rpx;
+  margin-bottom: 16rpx;
+  flex-shrink: 0;
+}
+
+.primary-btn {
+  background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
+  color: #ffffff;
+  border: none;
+  border-radius: 24rpx;
+  height: 60rpx;
+  font-size: 24rpx;
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 2rpx 8rpx rgba(255, 107, 107, 0.4);
+  transition: all 0.3s ease;
+}
+
+.primary-btn::after {
+  border: none;
+}
+
+.primary-btn:active {
+  transform: scale(0.98);
+  box-shadow: 0 2rpx 8rpx rgba(255, 107, 107, 0.4);
+}
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 移除不使用的样式 */
+
+/* 输入区域 */
+.input-section {
+  margin-bottom: 16rpx;
+  flex-shrink: 0;
+}
+
+.legacy-message-input {
+  width: 100%;
+  height: 120rpx;
+  background: #ffffff;
+  border: 1rpx solid #e1e8ed;
+  border-radius: 12rpx;
+  padding: 12rpx;
+  font-size: 20rpx;
+  color: #2c3e50;
+  box-sizing: border-box;
+  resize: none;
+}
+
+.legacy-message-input::placeholder {
+  color: #95a5a6;
+  font-size: 20rpx;
+}
+
+.char-count {
+  font-size: 16rpx;
+  color: #7f8c8d;
+  text-align: right;
+  margin-top: 4rpx;
+}
+
+/* 助手回复区域 */
+.reply-section {
+  background: rgba(255, 255, 255, 0.98);
+  border-radius: 12rpx;
+  padding: 16rpx;
+  margin-bottom: 12rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+  animation: fadeIn 0.4s ease-in-out;
+  flex-shrink: 0;
+  max-height: 200rpx;
+  overflow-y: auto;
+}
+
+.reply-header {
+  margin-bottom: 8rpx;
+}
+
+.reply-title {
+  font-size: 22rpx;
+  font-weight: 600;
+  color: #3498db;
+  display: block;
+  line-height: 1.2;
+}
+
+.reply-content {
+  background: #f8f9fa;
+  border-radius: 8rpx;
+  padding: 12rpx;
+  margin-bottom: 8rpx;
+}
+
+.reply-text {
+  font-size: 20rpx;
+  color: #2c3e50;
+  line-height: 1.4;
+  white-space: pre-wrap;
+  word-break: break-word;
+}
+
+.reply-actions {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.reply-close-btn {
+  background: #95a5a6;
+  color: #ffffff;
+  border: none;
+  border-radius: 20rpx;
+  height: 44rpx;
+  font-size: 20rpx;
+  font-weight: 500;
+  padding: 0 20rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.reply-close-btn::after {
+  border: none;
+}
+
+.reply-close-btn:active {
+  transform: scale(0.98);
+  background: #5a6268;
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(16rpx);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 底部信息 */
+.footer {
+  text-align: center;
+  padding: 8rpx 0;
+  flex-shrink: 0;
+}
+
+.footer-text {
+  font-size: 16rpx;
+  color: rgba(255, 255, 255, 0.7);
+}
+
+.footer-section .footer-text {
+  font-size: 20rpx;
+  color: #999999;
+  line-height: 1.4;
+}

+ 16 - 0
pages/product/index.js

@@ -0,0 +1,16 @@
+Page({
+  handleContactService: function () {
+    tt.navigateTo({
+      url: '/pages/index/index'
+    })
+  },
+
+  handleGoProduct: function () {
+  },
+
+  handleGoTrial: function () {
+    tt.redirectTo({
+      url: '/pages/trial/index'
+    })
+  }
+})

+ 4 - 0
pages/product/index.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "产品介绍",
+  "usingComponents": {}
+}

+ 88 - 0
pages/product/index.ttml

@@ -0,0 +1,88 @@
+<view class="product-page">
+  <view class="hero">
+    <text class="title">音乐数字工具产品介绍</text>
+    <text class="subtitle">音乐数字工具软件核心功能围绕音频处理、交互体验、资源管理、数据统计、多端适配五大维度,聚焦软件本身的技术能力与功能落地,覆盖歌唱、乐理、器乐、欣赏、创作全场景。</text>
+  </view>
+
+  <view class="section">
+    <text class="section-title">一、核心音频交互模块</text>
+    <view class="card">
+      <text class="item-title">1. 多模式音频播放与控制</text>
+      <text class="item-desc">支持范唱、伴奏、节奏、旋律、哼唱、唱名、男女声分轨播放,可自由切换轨道、调节音量占比;支持变速不变调、慢速跟练、分句播放;支持音频循环、断点续播、逐小节/逐音符精准定位。</text>
+    </view>
+    <view class="card">
+      <text class="item-title">2. 音高与节奏可视化交互</text>
+      <text class="item-desc">内置旋律线实时展示,可直观呈现音准与节奏变化;支持音高、节奏实时识别与反馈;内置可视化节拍器,支持多拍号切换与速度调节。</text>
+    </view>
+  </view>
+
+  <view class="section">
+    <text class="section-title">二、乐谱与器乐辅助功能</text>
+    <view class="card">
+      <text class="item-title">1. 动态乐谱展示与编辑</text>
+      <text class="item-desc">支持简谱、五线谱双向对照展示,歌词与乐谱同步高亮,可自由缩放与模式切换;支持勾画标注、修改音符、调整旋律走向;支持乐谱导出与分享。</text>
+    </view>
+    <view class="card">
+      <text class="item-title">2. 虚拟器乐与指法辅助</text>
+      <text class="item-desc">内置排箫、葫芦丝、陶笛、竖笛、口风琴等虚拟键盘/指板,支持指法动态高亮;支持多声部演示、声部静音与独奏切换;支持按乐器类型与曲目难度自动生成指法图谱。</text>
+    </view>
+  </view>
+
+  <view class="section">
+    <text class="section-title">三、AI智能交互与识别模块</text>
+    <view class="card">
+      <text class="item-title">智能识别与陪练评测</text>
+      <text class="item-desc">支持麦克风实时识别音准、节奏、指法准确性并自动标记偏差;支持片段选择、速度调节、逐音校验与偏差暂停提醒;支持完整性、准确性量化评分并生成反馈报告。</text>
+    </view>
+  </view>
+
+  <view class="section">
+    <text class="section-title">四、多媒体资源与创作模块</text>
+    <view class="card">
+      <text class="item-title">1. 多媒体资源整合与展示</text>
+      <text class="item-desc">支持高清音频、视频播放,可关联展示乐曲背景与创作者信息;支持资源分类、搜索、筛选与持续更新;支持外部音视频、图片、乐谱导入。</text>
+    </view>
+    <view class="card">
+      <text class="item-title">2. 简易编曲与创作功能</text>
+      <text class="item-desc">提供配器选择、旋律编辑、多轨混音等功能;支持节奏创作、旋律仿写与律动小游戏;支持作品导出、保存与多平台分享。</text>
+    </view>
+  </view>
+
+  <view class="section">
+    <text class="section-title">五、工具与管理模块</text>
+    <view class="card">
+      <text class="item-title">1. 可视化编辑与录制工具</text>
+      <text class="item-desc">内置音乐电子白板,支持书写与编辑五线谱/简谱并添加标注;支持屏幕+音频录制并进行简单剪辑;支持PPT、Word、Excel导入与播放。</text>
+    </view>
+    <view class="card">
+      <text class="item-title">2. 数据统计与云端服务</text>
+      <text class="item-desc">支持使用时长、操作频次、识别准确率等统计并生成可视化报表;支持资源、记录、作品云端备份;支持多端数据同步与设备间互通。</text>
+    </view>
+  </view>
+
+  <view class="section">
+    <text class="section-title">六、多端适配与拓展功能</text>
+    <text class="value-line">1. 支持电脑、平板、手机、电子白板等多设备适配,界面自适应调整</text>
+    <text class="value-line">2. 支持多用户分组与权限管控,实现分组展示与互动操作</text>
+    <text class="value-line">3. 预留灵活拓展接口,可按需求新增模块、对接外部资源</text>
+  </view>
+
+  <view class="section">
+    <text class="section-title">产品优势</text>
+    <text class="value-line">软件聚焦音频交互、智能识别、资源整合、多端适配四大核心能力,提供从音频播放、乐谱展示到智能交互、创作留存的全流程功能支持。</text>
+    <text class="value-line">可根据软件开发服务需求灵活适配各类音乐相关场景,满足不同客户的定制化开发诉求。</text>
+  </view>
+
+  <view class="contact-box">
+    <button class="contact-btn" bindtap="handleContactService">联系客服</button>
+  </view>
+
+  <view class="page-tabbar">
+    <view class="page-tab-item page-tab-item-active" bindtap="handleGoProduct">
+      <text class="page-tab-text page-tab-text-active">产品介绍</text>
+    </view>
+    <view class="page-tab-item" bindtap="handleGoTrial">
+      <text class="page-tab-text">申请试用</text>
+    </view>
+  </view>
+</view>

+ 110 - 0
pages/product/index.ttss

@@ -0,0 +1,110 @@
+.product-page {
+  min-height: 100vh;
+  box-sizing: border-box;
+  background: #f5f7fb;
+  padding: 24rpx 24rpx 140rpx 24rpx;
+}
+
+.hero {
+  background: linear-gradient(135deg, #667eea 0%, #6d8df6 100%);
+  border-radius: 20rpx;
+  padding: 28rpx;
+  margin-bottom: 24rpx;
+}
+
+.title {
+  display: block;
+  color: #ffffff;
+  font-size: 34rpx;
+  font-weight: 600;
+  margin-bottom: 12rpx;
+}
+
+.subtitle {
+  display: block;
+  color: rgba(255, 255, 255, 0.92);
+  font-size: 24rpx;
+  line-height: 1.6;
+}
+
+.section {
+  background: #ffffff;
+  border-radius: 16rpx;
+  padding: 20rpx;
+  margin-bottom: 20rpx;
+}
+
+.section-title {
+  display: block;
+  font-size: 28rpx;
+  color: #1f2d3d;
+  font-weight: 600;
+  margin-bottom: 16rpx;
+}
+
+.card {
+  background: #f8faff;
+  border: 1rpx solid #e6ecff;
+  border-radius: 12rpx;
+  padding: 16rpx;
+  margin-bottom: 12rpx;
+}
+
+.card:last-child {
+  margin-bottom: 0;
+}
+
+.item-title {
+  display: block;
+  color: #2b3a4d;
+  font-size: 26rpx;
+  font-weight: 600;
+  margin-bottom: 8rpx;
+}
+
+.item-desc {
+  display: block;
+  color: #4f627a;
+  font-size: 24rpx;
+  line-height: 1.6;
+}
+
+.tags {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.tag {
+  background: #eef4ff;
+  color: #3f5f9f;
+  border-radius: 999rpx;
+  font-size: 22rpx;
+  padding: 10rpx 18rpx;
+  margin-right: 12rpx;
+  margin-bottom: 12rpx;
+}
+
+.value-line {
+  display: block;
+  color: #33475b;
+  font-size: 24rpx;
+  line-height: 1.8;
+}
+
+.contact-box {
+  margin-top: 28rpx;
+}
+
+.contact-btn {
+  height: 84rpx;
+  border-radius: 42rpx;
+  background: #4facfe;
+  color: #ffffff;
+  font-size: 28rpx;
+  font-weight: 600;
+  border: none;
+}
+
+.contact-btn::after {
+  border: none;
+}

+ 65 - 0
pages/trial/index.js

@@ -0,0 +1,65 @@
+Page({
+  data: {
+    formData: {
+      occupation: '',
+      contactName: '',
+      phone: '',
+      organization: '',
+      notes: ''
+    }
+  },
+
+  handleInputChange: function (e) {
+    const field = e.currentTarget.dataset.field
+    const value = e.detail.value
+    const next = Object.assign({}, this.data.formData, { [field]: value })
+    this.setData({ formData: next })
+  },
+
+  handleSubmit: function () {
+    const data = this.data.formData
+
+    if (!data.occupation.trim()) {
+      tt.showToast({
+        title: '请填写职业',
+        icon: 'none',
+        duration: 2000
+      })
+      return
+    }
+
+    if (!data.contactName.trim() || !data.phone.trim()) {
+      tt.showToast({
+        title: '请完善联系人与手机号',
+        icon: 'none',
+        duration: 2000
+      })
+      return
+    }
+
+    tt.showToast({
+      title: '提交成功,稍后联系您',
+      icon: 'success',
+      duration: 2000
+    })
+
+    this.setData({
+      formData: {
+        occupation: '',
+        contactName: '',
+        phone: '',
+        organization: '',
+        notes: ''
+      }
+    })
+  },
+
+  handleGoProduct: function () {
+    tt.redirectTo({
+      url: '/pages/product/index'
+    })
+  },
+
+  handleGoTrial: function () {
+  }
+})

+ 4 - 0
pages/trial/index.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "申请试用",
+  "usingComponents": {}
+}

+ 77 - 0
pages/trial/index.ttml

@@ -0,0 +1,77 @@
+<view class="trial-page">
+  <view class="hero">
+    <text class="title">申请试用</text>
+    <text class="subtitle">填写以下信息,我们会尽快与您联系并安排产品试用。</text>
+  </view>
+
+  <view class="form-card">
+    <view class="form-item">
+      <text class="label">职业</text>
+      <input
+        class="input"
+        placeholder="请输入职业"
+        value="{{formData.occupation}}"
+        data-field="occupation"
+        bindinput="handleInputChange"
+      />
+    </view>
+
+    <view class="form-item">
+      <text class="label">联系人</text>
+      <input
+        class="input"
+        placeholder="请输入联系人姓名"
+        value="{{formData.contactName}}"
+        data-field="contactName"
+        bindinput="handleInputChange"
+      />
+    </view>
+
+    <view class="form-item">
+      <text class="label">手机号</text>
+      <input
+        class="input"
+        type="number"
+        maxlength="11"
+        placeholder="请输入手机号"
+        value="{{formData.phone}}"
+        data-field="phone"
+        bindinput="handleInputChange"
+      />
+    </view>
+
+    <view class="form-item">
+      <text class="label">单位/学校</text>
+      <input
+        class="input"
+        placeholder="请输入单位或学校名称"
+        value="{{formData.organization}}"
+        data-field="organization"
+        bindinput="handleInputChange"
+      />
+    </view>
+
+    <view class="form-item">
+      <text class="label">试用需求</text>
+      <textarea
+        class="textarea"
+        maxlength="300"
+        placeholder="请简要描述您的使用场景和试用诉求"
+        value="{{formData.notes}}"
+        data-field="notes"
+        bindinput="handleInputChange"
+      ></textarea>
+    </view>
+
+    <button class="submit-btn" bindtap="handleSubmit">提交申请</button>
+  </view>
+
+  <view class="page-tabbar">
+    <view class="page-tab-item" bindtap="handleGoProduct">
+      <text class="page-tab-text">产品介绍</text>
+    </view>
+    <view class="page-tab-item page-tab-item-active" bindtap="handleGoTrial">
+      <text class="page-tab-text page-tab-text-active">申请试用</text>
+    </view>
+  </view>
+</view>

+ 84 - 0
pages/trial/index.ttss

@@ -0,0 +1,84 @@
+.trial-page {
+  min-height: 100vh;
+  box-sizing: border-box;
+  background: #f5f7fb;
+  padding: 24rpx 24rpx 140rpx 24rpx;
+}
+
+.hero {
+  background: linear-gradient(135deg, #5c84ff 0%, #6aa7ff 100%);
+  border-radius: 20rpx;
+  padding: 28rpx;
+  margin-bottom: 24rpx;
+}
+
+.title {
+  display: block;
+  color: #ffffff;
+  font-size: 34rpx;
+  font-weight: 600;
+  margin-bottom: 10rpx;
+}
+
+.subtitle {
+  display: block;
+  color: rgba(255, 255, 255, 0.92);
+  font-size: 24rpx;
+  line-height: 1.6;
+}
+
+.form-card {
+  background: #ffffff;
+  border-radius: 16rpx;
+  padding: 20rpx;
+}
+
+.form-item {
+  margin-bottom: 18rpx;
+}
+
+.label {
+  display: block;
+  color: #2c3e50;
+  font-size: 24rpx;
+  margin-bottom: 8rpx;
+}
+
+.input {
+  width: 100%;
+  height: 76rpx;
+  background: #f7f9fc;
+  border: 1rpx solid #dfe6f2;
+  border-radius: 12rpx;
+  box-sizing: border-box;
+  padding: 0 16rpx;
+  font-size: 24rpx;
+  color: #2c3e50;
+}
+
+.textarea {
+  width: 100%;
+  height: 180rpx;
+  background: #f7f9fc;
+  border: 1rpx solid #dfe6f2;
+  border-radius: 12rpx;
+  box-sizing: border-box;
+  padding: 14rpx 16rpx;
+  font-size: 24rpx;
+  color: #2c3e50;
+}
+
+.submit-btn {
+  margin-top: 14rpx;
+  height: 84rpx;
+  border-radius: 42rpx;
+  background: #4facfe;
+  color: #ffffff;
+  font-size: 28rpx;
+  font-weight: 600;
+  border: none;
+}
+
+.submit-btn::after {
+  border: none;
+}

+ 15 - 0
project.config.json

@@ -0,0 +1,15 @@
+{
+    "setting": {
+        "urlCheck": true,
+        "es6": true,
+        "postcss": true,
+        "minified": true,
+        "newFeature": true,
+        "autoCompile": true,
+        "compileHotReLoad": true,
+        "nativeCompile": true
+    },
+    "appid": "tt8a26fc9b1447aa6a01",
+    "projectname": "yyszkt_help",
+    "douyinProjectType": "native"
+}