Browse Source

合并目前代码

qw 5 months ago
parent
commit
68f7946017

+ 126 - 0
pages/ModelTrain/ModelTrain.js

@@ -0,0 +1,126 @@
+Page({
+  data: {
+    rows: [], // 所有表格数据
+    currentRow: null, // 当前选中的表格行
+    filteredRows: null, // 过滤后的表格数据
+    tableHeaders: [
+      "数据集名称","数据集描述","数据集类型","数据条数",
+      "数据集状态","更新时间"
+    ],
+    types: [{ name: 'all' }, { name: 'reduce' }, { name: 'reflux' }], // 数据种类
+    currentType: 'all', // 当前选中的数据种类
+  },
+
+  // 页面加载时获取表格数据
+  onLoad: function() {
+    this.LoadData();
+  },
+
+  LoadData: function() {
+    wx.request({
+      url: 'http://localhost:5000/table',
+      method: 'POST',
+      header: {
+        'Content-Type': 'application/json'
+      },
+      data: {
+        table: 'Datasets'
+      },
+      success: (res) => {
+        console.log('后端返回数据:', res.data.rows); // 打印返回数据,确认格式
+        
+        if (res.data && Array.isArray(res.data.rows)) {
+          const rows = res.data.rows.map(row => {
+            return {
+              'id': row.Dataset_ID,
+              'name': row.Dataset_name,
+              'description': row.Dataset_description,
+              'type': row.Dataset_type,
+              'count': row.Row_count,
+              'status': row.Status,
+              'uploadTime': row.Uploaded_at,
+            };
+          });
+          console.log(rows);
+          this.setData({
+            rows: rows,
+            filteredRows: rows,
+          });
+        } else {
+          wx.showToast({
+            title: '获取数据失败',
+            icon: 'none'
+          });
+        }
+      },
+      fail: (err) => {
+        wx.showToast({
+          title: '请求失败,请重试',
+          icon: 'none'
+        });
+        console.error('请求失败:', err);
+      }
+    });
+  },
+
+  // 处理行点击事件
+  onRowClick: function(e) {
+    const index = e.currentTarget.dataset.index;
+    const selectedRow = this.data.filteredRows[index];
+    this.setData({
+      currentRow: this.data.filteredRows[index] ? {...this.data.filteredRows[index], index} : null
+    });
+    console.log('选中的行信息:', selectedRow); // 打印当前选中行的信息
+  },
+  
+  // 处理数据种类改变事件
+  onTypeChange: function(e) {
+    const type = this.data.types[e.detail.value].name;
+    this.setData({
+      currentType: type,
+      filteredRows: type === 'all' ? this.data.rows : this.data.rows.filter(row => row.type === type)
+    });
+  },
+
+  // 处理训练模型按钮点击事件
+  trainModel: function() {
+    const { currentRow } = this.data;
+    if (!currentRow) {
+      wx.showToast({
+        title: '请先选择一行数据',
+        icon: 'none'
+      });
+      return;
+    }
+    const { id, type } = currentRow;
+    const trainData = {
+      model_type: "RandomForest",
+      model_name: "ForestModel1",
+      model_description: "A random forest model trained on current data.",
+      data_type: type,
+      dataset_id: id
+    };
+    wx.request({
+      url: 'http://localhost:5000/train-and-save-model', // 假设这是你的接口地址
+      method: 'POST',
+      header: {
+        'Content-Type': 'application/json'
+      },
+      data: trainData,
+      success: (res) => {
+        console.log('模型训练成功:', res);
+        wx.showToast({
+          title: '模型训练完成',
+          icon: 'success'
+        });
+      },
+      fail: (err) => {
+        console.error('模型训练失败:', err);
+        wx.showToast({
+          title: '模型训练失败',
+          icon: 'none'
+        });
+      }
+    });
+  }
+})

+ 6 - 0
pages/ModelTrain/ModelTrain.json

@@ -0,0 +1,6 @@
+{
+  "usingComponents": { },
+  "navigationBarTitleText": "模型训练",
+  "navigationBarBackgroundColor": "#dbdbdb",  
+  "navigationBarTextStyle": "black"
+}

+ 53 - 0
pages/ModelTrain/ModelTrain.wxml

@@ -0,0 +1,53 @@
+<!-- 数据种类选择标题 -->
+<view class="picker-title">数据集种类:</view>
+
+<!-- 数据种类选择下拉框 -->
+<picker mode="selector" range="{{types}}" range-key="name" bindchange="onTypeChange">
+  <view class="picker-container">
+    <view class="picker">
+      {{currentType === 'all' ? '全部数据' : currentType}}
+    </view>
+    <view class="picker-arrow"></view> <!-- 三角形样式 -->
+  </view>
+</picker>
+
+<!-- 滚动区域 -->
+<scroll-view class="table-container" scroll-x="true" scroll-with-animation="true">
+  <!-- 数据加载中 -->
+  <view wx:if="{{loading}}" class="loading">数据加载中,请稍候...</view>
+
+  <!-- 无数据提示 -->
+  <view wx:if="{{!loading && filteredRows.length === 0}}" class="no-data">暂无数据</view>
+
+  <!-- 表格 -->
+  <view class="table-body">
+    <view class="table-header">
+      <!-- 添加单选框 -->
+      <view class="table-cell"></view>
+      <view class="table-cell" wx:for="{{tableHeaders}}" wx:key="index">{{item}}</view>
+    </view>
+
+    <block wx:for="{{filteredRows}}" wx:key="index">
+      <view class="table-row" bindtap="onRowClick" data-index="{{index}}">
+        <!-- 单选框列 -->
+        <view class="table-cell">
+          <radio 
+            value="{{index}}" checked="{{currentRow && currentRow.index === index}}" 
+            class="{{currentRow && currentRow.index === index ? 'radio-checked' : 'radio-unchecked'}}"
+            />
+        </view>
+        <!-- 数据列 -->
+        <view class="table-cell">{{item.name}}</view>
+        <view class="table-cell">{{item.description}}</view>
+        <view class="table-cell">{{item.type}}</view>
+        <view class="table-cell">{{item.count}}</view>
+        <view class="table-cell">{{item.status}}</view>
+        <view class="table-cell">{{item.uploadTime}}</view>
+      </view>
+    </block>
+  </view>
+</scroll-view>
+
+<view class="button-container">
+  <button bindtap="trainModel">训练</button>
+</view>

+ 139 - 0
pages/ModelTrain/ModelTrain.wxss

@@ -0,0 +1,139 @@
+
+/* 表格容器 */
+.table-container {
+  width: 100%;
+  overflow-x: auto; /* 启用横向滚动 */
+  white-space: nowrap; /* 禁止换行 */
+  background-color: #fff;
+  border: 1rpx solid #ddd;
+  margin-top: 10rpx; /* 添加上边距,确保不会和顶部元素重叠 */
+  white-space: nowrap; /* 禁止换行 */
+}
+
+/* 表头样式 */
+.table-header {
+  display: flex;
+  background-color: #61E054; /* 表头背景色 */
+  font-weight: bold;
+  text-align: center;
+}
+
+/* 表格单元格样式 */
+.table-cell {
+  flex: none;
+  width: 250rpx; /* 固定宽度 */
+  padding: 10rpx;
+  text-align: center;
+  font-size: 28rpx;
+  color: #030803; /* 表头文字颜色 */
+  border-right: 1rpx solid #ddd;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+/* 表格行样式 */
+.table-row:nth-child(odd) {
+  background-color: #E4FBE5; /* 奇数行背景色 */
+}
+
+.table-row:nth-child(even) {
+  background-color: #fff; /* 偶数行背景色 */
+}
+
+/* 表格内容样式 */
+.table-body {
+  display: flex;
+  flex-direction: column;
+  width: max-content;
+}
+
+.table-row {
+  display: flex;
+  flex-direction: row;
+  border-bottom: 1rpx solid #ddd;
+}
+
+/* 单选框样式 */
+.radio {
+  display: inline-block;
+  margin-right: 10px; /* 单选框之间的间隔 */
+}
+
+/* 单选框选中时的样式 */
+.radio-checked {
+  color: #1AAD19; /* 微信小程序主题色 */
+}
+
+/* 单选框未选中时的样式 */
+.radio-unchecked {
+  color: #ccc; /* 灰色表示未选中 */
+}
+
+/* 按钮通用样式 */
+.button-container button {
+  width: 50%; /* 按钮宽度100%,占满容器宽度 */
+  height: 50px; /* 按钮高度 */
+  line-height: 50px; /* 行高与按钮高度一致,使文本垂直居中 */
+  background-color: #1AAD19; /* 微信绿 */
+  color: white; /* 文字颜色为白色 */
+  border-radius: 5px; /* 圆角边框 */
+  font-size: 16px; /* 字体大小 */
+  margin-top: 20px;
+}
+
+/* 按钮点击效果 */
+.button-container button:active {
+  background-color: #179B16; /* 点击时背景颜色变深 */
+}
+
+
+/* 下拉框容器样式 */
+.picker-container {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 16px; /* 字体大小 */
+  color: #333; /* 字体颜色 */
+  padding: 8px 12px; /* 内边距 */
+  background-color: #fff; /* 背景颜色 */
+  border: 1px solid #ddd; /* 边框 */
+  border-radius: 4px; /* 圆角边框 */
+  width: 200px; /* 固定宽度 */
+  margin-left: auto; /* 自动左边距 */
+  margin-right: auto; /* 自动右边距 */
+  box-sizing: border-box; /* 确保边框和内边距包含在宽度内 */
+}
+
+/* 下拉框样式 */
+.picker {
+  flex-grow: 1; /* 使下拉框占据剩余空间 */
+  text-align: left; /* 文字左对齐 */
+}
+
+/* 三角形样式 */
+.picker-arrow {
+  width: 0;
+  height: 0;
+  border-left: 5px solid transparent;
+  border-right: 5px solid transparent;
+  border-top: 5px solid #333; /* 三角形颜色 */
+  margin-left: 10px; /* 与下拉框文本的间隔 */
+}
+
+/* 下拉框标题样式 */
+.picker-title {
+  font-size: 16px; /* 字体大小 */
+  font-weight: bold; /* 字体加粗 */
+  color: #333; /* 字体颜色 */
+  margin-bottom: 10px; /* 与下拉框之间的间隔 */
+  text-align: center; /* 文字居中 */
+  padding: 8px 0; /* 上下内边距 */
+  background-color: #f0f0f0; /* 背景颜色 */
+  border: 1px solid #ddd; /* 边框 */
+  border-radius: 4px; /* 圆角边框 */
+  width: 200px; /* 固定宽度 */
+  margin-left: auto; /* 自动左边距 */
+  margin-right: auto; /* 自动右边距 */
+  box-sizing: border-box; /* 确保边框和内边距包含在宽度内 */
+}

+ 0 - 36
pages/RoleSelectionPage/RoleSelectionPage.js

@@ -1,36 +0,0 @@
-Component({
-  data: {
-  },
-  methods: {
-    //普通用户
-    selectRegularUser(e) {
-      let data = e.currentTarget.dataset;
-      let url = data.path;
-        // 存储普通用户信息到本地缓存
-        wx.setStorageSync('userRole', 'regular');  // 存储角色为普通用户
-        wx.setStorageSync('rolePath', url); // 存储路径(可选)
-      // 可能还需要进行页面跳转或其他逻辑
-      wx.reLaunch({
-        url: '/shoping/Home/Home',
-      });
-    },
-    //管理员
-    selectAdmin(e) {
-      let data = e.currentTarget.dataset;
-      let url = data.path;
-      // 存储管理员信息到本地缓存
-      wx.setStorageSync('userRole', 'admin');  // 存储角色为管理员
-      wx.setStorageSync('rolePath', url); // 存储路径(可选)
-      // 可能还需要进行页面跳转或其他逻辑
-      wx.reLaunch({
-        url: '/pages/threshold/threshold',
-      });
-    },
-    // 隐藏返回首页按钮
-    onShow: function() {
-      if(wx.canIUse('hideHomeButton')) {
-        wx.hideHomeButton();
-      }
-    }
-  },
-});

+ 0 - 6
pages/RoleSelectionPage/RoleSelectionPage.json

@@ -1,6 +0,0 @@
-{
-  "usingComponents": {},
-  "navigationBarTitleText": "选择权限", 
-  "navigationBarBackgroundColor": "#ffffff",  
-  "navigationBarTextStyle": "black"  
-}

+ 0 - 7
pages/RoleSelectionPage/RoleSelectionPage.wxml

@@ -1,7 +0,0 @@
-<!-- pages/role-selection/role-selection.wxml -->
-<view class="container">
-  <button class="full-width-button" bindtap="selectRegularUser" data-path="/shoping/index/index">普通用户</button>
-
-  <button class="full-width-button" bindtap="selectAdmin">管理员</button>
-</view>
-<custom-tab-bar></custom-tab-bar>

+ 0 - 27
pages/RoleSelectionPage/RoleSelectionPage.wxss

@@ -1,27 +0,0 @@
-/* 父容器样式 */
-.container {
-  display: flex;
-  flex-direction: column; /* 垂直排列 */
-  align-items: center;    /* 居中对齐 */
-  padding: 20px 0;        /* 增加上下内边距 */
-  margin: 150px  20px 20px  20px;     /* 增加顶部外边距 */
-}
-
-/* 按钮样式 */
-.full-width-button {
-  width: 100%;            /* 按钮占满宽度 */
-  padding: 15px 0;        /* 按钮内边距,控制高度 */
-  margin: 15px 0;         /* 按钮间距 */
-  background-color: #3EC01E; /* 按钮背景颜色 */
-  color: white;           /* 按钮文字颜色 */
-  font-size: 18px;        /* 按钮文字大小 */
-  border: none;           /* 去除按钮边框 */
-  outline: none;          /* 去除焦点边框 */
-  text-align: center;     /* 文字居中 */
-  border-radius: 5px;     /* 圆角效果 */
-}
-
-/* 按钮点击效果 */
-.full-width-button:active {
-  background-color: #299A0C; /* 按下按钮时的颜色变化 */
-}

+ 37 - 34
pages/Staff/Staff.js

@@ -1,11 +1,15 @@
 Page({
   data: {
     isLogin: false,  // 登录状态
-    userInfo: {},    // 存储用户信息(头像、昵称、用户名、密码)
+    validUsers: {    // 存储用户名、密码和头像信息
+      username: '',
+      password: '',
+      avatarUrl: ''
+    },
     isHidden: true,  // 登录弹窗状态
   },
 
-  // 页面加载时获取缓存的昵称、头像、用户名、密码
+  // 页面加载时获取缓存的用户信息
   onLoad() {
     this.loadUserInfo();  // 调用加载用户信息的方法
   },
@@ -14,8 +18,7 @@ Page({
   onShow() {
     this.loadUserInfo();  // 每次进入页面时刷新用户信息
     if (typeof this.getTabBar === 'function' && this.getTabBar()) {
-      this.getTabBar().setData({
-      });
+      this.getTabBar().setData({});
     }
     // 隐藏返回首页按钮
     if (wx.canIUse('hideHomeButton')) {
@@ -26,38 +29,38 @@ Page({
   // 加载用户信息并更新页面
   loadUserInfo() {
     const storedUserInfo = wx.getStorageSync('userInfo');  // 获取缓存中的用户信息
-    if (storedUserInfo) {
-      // 如果缓存中有用户信息,更新页面上的数据
+    if (storedUserInfo && storedUserInfo.username && storedUserInfo.password) {
+      // 如果缓存中有用户名和密码,更新页面上的数据
       this.setData({
-        userInfo: storedUserInfo,  // 更新用户信息
-        isLogin: true, // 设置登录状态为 true
+        validUsers: storedUserInfo,  // 更新用户信息
+        isLogin: true,  // 设置登录状态为 true
       });
     }
   },
 
-  // 获取用户头像
-  getAvatar(e) {
-    const avatarUrl = e.detail.avatarUrl;
+  // 获取用户的用户名
+  getUsername(e) {
+    const username = e.detail.value;
     this.setData({
-      'userInfo.avatarUrl': avatarUrl
+      'validUsers.username': username
     });
 
-    // 保存头像到缓存
+    // 保存用户名到缓存
     let userInfo = wx.getStorageSync('userInfo') || {};
-    userInfo.avatarUrl = avatarUrl;
+    userInfo.username = username;
     wx.setStorageSync('userInfo', userInfo);
   },
 
-  // 获取用户昵称
-  getName(e) {
-    const nickName = e.detail.value;
+  // 获取用户的密码
+  getPassword(e) {
+    const password = e.detail.value;
     this.setData({
-      'userInfo.nickName': nickName
+      'validUsers.password': password
     });
 
-    // 保存昵称到缓存
+    // 保存密码到缓存
     let userInfo = wx.getStorageSync('userInfo') || {};
-    userInfo.nickName = nickName;
+    userInfo.password = password;
     wx.setStorageSync('userInfo', userInfo);
   },
 
@@ -68,13 +71,6 @@ Page({
     });
   },
 
-  // 编辑个人资料
-  EditProfile() {
-    wx.navigateTo({
-      url: '/shoping/EditProfile/EditProfile'
-    });
-  },
-
   // 取消登录弹窗
   potNo() {
     this.setData({
@@ -82,19 +78,26 @@ Page({
     });
   },
 
+  // 编辑个人资料
+  EditProfile() {
+    wx.navigateTo({
+      url: '/shoping/EditProfile/EditProfile'
+    });
+  },
+
   // 确认登录弹窗
   popYes() {
-    const { avatarUrl, nickName, username, password } = this.data.userInfo;
-    if (!avatarUrl || !nickName || !username || !password) {
+    const { username, password } = this.data.validUsers;
+    if (!username || !password) {
       wx.showToast({
         icon: 'error',
-        title: '请填写头像、昵称、用户名和密码',
+        title: '请填写用户名和密码',
       });
       return;
     }
 
-    // 保存头像、昵称、用户名和密码到缓存
-    wx.setStorageSync('userInfo', this.data.userInfo);
+    // 保存用户名和密码到缓存
+    wx.setStorageSync('userInfo', this.data.validUsers);
     this.setData({
       isLogin: true,  // 设置登录状态为 true
       isHidden: true, // 隐藏弹窗
@@ -116,12 +119,12 @@ Page({
     // 重置登录状态
     this.setData({
       isLogin: false,
-      userInfo: {}
+      validUsers: {}  // 清空用户信息
     });
 
     // 跳转到登录页面
     wx.reLaunch({
-      url: '/pages/admin/admin' // 登录页面的路径
+      url: '/shoping/Home/Home' // 登录页面的路径
     });
   }
 });

+ 3 - 3
pages/Staff/Staff.wxml

@@ -2,14 +2,14 @@
   <!-- 点击头像区域,判断是否登录 -->
   <view class="logo" bindtap="goLogin" hover-class="{{!isLogin ? 'logo-hover' : ''}}">
     <!-- 显示用户头像(如果已登录并且有头像) -->
-    <image class="logo-img" wx:if="{{isLogin && userInfo && userInfo.avatarUrl}}" src="{{ userInfo.avatarUrl }}" />
+    <image class="logo-img" wx:if="{{isLogin && validUsers && validUsers.avatarUrl}}" src="{{ validUsers.avatarUrl }}" />
     <!-- 未登录或没有头像时,显示默认头像 -->
-    <image class="logo-img" wx:if="{{!isLogin || !userInfo.avatarUrl}}" src="/assets/taddar/me.png" />
+    <image class="logo-img" wx:if="{{!isLogin || !validUsers.avatarUrl}}" src="/assets/taddar/me.png" />
     
     <!-- 显示用户昵称,如果昵称存在,则显示昵称,若没有则显示用户名 -->
     <view class="logo-title">
       <text class="uer-name">
-        Hi,{{ isLogin ? (userInfo.nickName || userInfo.username || '未登录') : '未登录' }}
+        Hi,{{ isLogin ? validUsers.username || '未登录' : '未登录' }}
       </text>
       <!-- 未登录时显示登录图标 -->
       <image class="go-login" wx:if="{{!isLogin}}" src="/assets/taddar/right (1).png" />

+ 252 - 90
pages/Visualizatio/Visualizatio.js

@@ -1,6 +1,8 @@
 Page({
   data: {
     isEditing: false,
+    tableName: 'current_reduce', // 确保这个表名在页面中是有效的
+    fileFormat: 'excel', // 默认是 Excel 格式
     shoopingtext: "", // 搜索框内容
     filteredRows: [], // 表格过滤后的数据
     rows: [], // 所有表格数据
@@ -9,25 +11,18 @@ Page({
     currentRow: null, // 当前选中的表格行
     // 新增数据弹窗的输入框内容
     newData: {
-      Sample_ID: "",
+      id: "",
+      Q_over_b: "",
+      pH: "",
       OM: "",
       CL: "",
-      CEC: "",
       H: "",
-      HN: "",
-      Al: "",
-      free_alumina: "",
-      free_iron_oxides: "",
-      pH: "",
-      final_pH: "",
-      Collection_location: "",
-      Collection_date: ""
+      Al: ""
     },
     // 中文表头内容,动态生成
     tableHeaders: [
-      "序号", "0天 pH", "有机质含量 (g/kg)", "土壤粘粒重量 (g/kg)", "阳离子交换量 (cmol/kg)", 
-      "氢离子含量 (cmol/kg)", "铵离子含量 (mg/kg)", "铝离子含量 (cmol/kg)", "游离氧化铝 (g/kg)", 
-      "游离氧化铁 (g/kg)", "105天 pH", "采集位置", "采集日期"
+      "序号", "比值", "酸碱度", "有机质含量", "氯离子含量",
+      "氢离子含量","铝离子含量"
     ]
   },
 
@@ -44,7 +39,7 @@ Page({
         'Content-Type': 'application/json'
       },
       data: {
-        table: 'Soil_samples'
+        table: 'current_reduce'
     },
     success: (res) => {
       console.log('后端返回数据:', res.data.rows); // 打印返回数据,确认格式
@@ -52,19 +47,13 @@ Page({
       if (res.data && Array.isArray(res.data.rows)) {
         const rows = res.data.rows.map(row => {
           return {
-            'Sample_ID': row[0],
-            'pH': row[1],
-            'OM': row[2],
-            'CL': row[3],
-            'CEC': row[4],
+            'id': row[0],
+            'Q_over_b':  row[1],
+            'pH': row[2],
+            'OM': row[3],
+            'CL': row[4],
             'H': row[5],
-            'HN': row[6],
-            'Al': row[7],
-            'free_alumina': row[8],
-            'free_iron_oxides': row[9],
-            'final_pH': row[10],
-            'Collection_location': row[11],
-            'Collection_date': row[12]
+            'Al': row[6]
           };
         });
 
@@ -108,90 +97,265 @@ Page({
     });
   },
 
+  // 下载模板函数
+  onDownloadTemplate: function() {
+    wx.showLoading({
+      title: '下载中...',
+    });
+  
+    const tableName = 'current_reduce';  // 或者根据需要选择表名
+    const format = 'excel';  // 或者 'csv' 作为模板格式
+  
+    wx.request({
+      url: `http://localhost:5000/download_template?table=${tableName}&format=${format}`,
+      method: 'GET',
+      responseType: 'arraybuffer',  // 处理二进制文件
+      success: (res) => {
+        wx.hideLoading();
+  
+        // 确保响应体返回的数据是有效的文件
+        if (res.statusCode === 200) {
+          const fileType = format === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'text/csv';
+  
+          // 生成唯一的文件名,添加时间戳以确保唯一性
+          const timestamp = new Date().getTime();
+          const fileName = `${tableName}_template_${timestamp}.${format}`;
+          const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
+  
+          // 使用文件系统管理器保存文件
+          const fs = wx.getFileSystemManager();
+          fs.writeFile({
+            filePath: filePath,
+            data: res.data,
+            encoding: 'binary',
+            success: () => {
+              wx.showToast({
+                title: '文件已保存',
+                icon: 'success'
+              });
+              // 触发文件下载
+              wx.openDocument({
+                filePath: filePath,
+                fileType: format === 'excel' ? 'xlsx' : 'csv',
+                success: () => {
+                  console.log('文件打开成功');
+                },
+                fail: (error) => {
+                  console.error('文件打开失败', error);
+                  wx.showToast({
+                    title: '打开文件失败',
+                    icon: 'none'
+                  });
+                }
+              });
+            },
+            fail: (err) => {
+              wx.showToast({
+                title: '文件保存失败',
+                icon: 'none'
+              });
+              console.error('文件保存失败', err);
+            }
+          });
+        } else {
+          wx.showToast({
+            title: '下载失败',
+            icon: 'none'
+          });
+        }
+      },
+      fail: (err) => {
+        wx.hideLoading();
+        wx.showToast({
+          title: '请求失败,请重试',
+          icon: 'none'
+        });
+        console.error('请求失败:', err);
+      }
+    });
+  },  
+
+   // 导出数据按钮点击事件
+   onExport: function () {
+    const tableName = this.data.tableName;
+    const fileFormat = this.data.fileFormat;
+
+    wx.showLoading({
+      title: '导出中...',
+    });
+
+    // 向后端发送请求,获取表格数据并导出
+    wx.request({
+      url: `http://localhost:5000/export_data?table=${tableName}&format=${fileFormat}`,
+      method: 'GET',
+      responseType: 'arraybuffer',  // 处理二进制文件
+      success: (res) => {
+        wx.hideLoading();
+
+        // 确保响应体返回的数据是有效的文件
+        if (res.statusCode === 200) {
+          const fileName = `${tableName}_data.${fileFormat === 'excel' ? 'xlsx' : 'csv'}`;
+          const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
+
+          // 保存文件到本地
+          wx.getFileSystemManager().writeFile({
+            filePath: filePath,
+            data: res.data,
+            encoding: 'binary',
+            success: () => {
+              wx.showToast({
+                title: '文件已保存',
+                icon: 'success'
+              });
+
+              // 打开已保存的文件
+              wx.openDocument({
+                filePath: filePath,
+                fileType: fileFormat === 'excel' ? 'xlsx' : 'csv',
+                success: () => {
+                  console.log('文件打开成功');
+                },
+                fail: (error) => {
+                  console.error('文件打开失败', error);
+                  wx.showToast({
+                    title: '打开文件失败',
+                    icon: 'none'
+                  });
+                }
+              });
+            },
+            fail: (err) => {
+              wx.showToast({
+                title: '文件保存失败',
+                icon: 'none'
+              });
+              console.error('文件保存失败', err);
+            }
+          });
+        } else {
+          wx.showToast({
+            title: '导出失败,请重试',
+            icon: 'none'
+          });
+        }
+      },
+      fail: (err) => {
+        wx.hideLoading();
+        wx.showToast({
+          title: '请求失败,请重试',
+          icon: 'none'
+        });
+        console.error('请求失败:', err);
+      }
+    });
+  },
+
+  // 导入数据功能
+  onImport: function () {
+    wx.chooseMessageFile({
+      count: 1,
+      type: 'file',
+      extension: ['xlsx', 'csv'], // 允许上传的文件类型
+      success: (res) => {
+        const filePath = res.tempFiles[0].path; // 获取文件临时路径
+        const fileName = res.tempFiles[0].name;
+
+        wx.showLoading({
+          title: '上传中...',
+        });
+
+        // 上传文件到后端
+        wx.uploadFile({
+          url: 'http://localhost:5000/import_data', // 后端处理导入的接口
+          filePath: filePath,
+          name: 'file',
+          formData: {
+            table: this.data.tableName, // 表名,后端根据需要解析数据
+            fileName: fileName
+          },
+          success: (res) => {
+            wx.hideLoading();
+            const responseData = JSON.parse(res.data);
+
+            if (responseData.success) {
+              wx.showToast({
+                title: '导入成功',
+                icon: 'success'
+              });
+
+              // 重新加载数据
+              this.LoadData();
+            } else {
+              wx.showToast({
+                title: '导入失败,请检查文件格式',
+                icon: 'none'
+              });
+            }
+          },
+          fail: (err) => {
+            wx.hideLoading();
+            wx.showToast({
+              title: '导入失败,请重试',
+              icon: 'none'
+            });
+            console.error('文件上传失败:', err);
+          }
+        });
+      },
+      fail: (err) => {
+        console.error('文件选择失败:', err);
+      }
+    });
+  },
+
   // 新增按钮点击,显示新增弹窗
   onAdd: function() {
     console.log("新增按钮被点击了");  // 调试日志
     this.setData({
       showAddModal: true,
       newData: { // 重置新增数据
-        OM: "",
-        CL: "",
-        CEC: "",
-        H: "",
-        HN: "",
-        Al: "",
-        free_alumina: "",
-        free_iron_oxides: "",
-        pH: "",
-        final_pH: "",
-        Collection_location: "",
-        Collection_date: ""
+      Q_over_b: "",
+      pH: "",
+      OM: "",
+      CL: "",
+      H: "",
+      Al: ""
       }
     });
     console.log("showAddModal: ", this.data.showAddModal);  // 确认数据更新
   },
 
   // 输入框绑定:更新新增数据的对应字段
-  onInputOM: function(e) {
+  onInputQ_over_b: function(e) {
     this.setData({
-      'newData.OM': e.detail.value
+      'newData.Q_over_b': e.detail.value
     });
   },
-  onInputCL: function(e) {
+  onInputpH: function(e) {
     this.setData({
-      'newData.CL': e.detail.value
+      'newData.pH': e.detail.value
     });
   },
-  onInputCEC: function(e) {
+  onInputOM: function(e) {
     this.setData({
-      'newData.CEC': e.detail.value
+      'newData.OM': e.detail.value
     });
   },
-  onInputHplus: function(e) {
+  onInputCL: function(e) {
     this.setData({
-      'newData.H': e.detail.value
+      'newData.CL': e.detail.value
     });
   },
-  onInputHN: function(e) {
+  onInputH: function(e) {
     this.setData({
-      'newData.HN': e.detail.value
+      'newData.H': e.detail.value
     });
   },
-  onInputAl3plus: function(e) {
+  onInputAl: function(e) {
     this.setData({
       'newData.Al': e.detail.value
     });
   },
-  onInputAlumina: function(e) {
-    this.setData({
-      'newData.free_alumina': e.detail.value
-    });
-  },
-  onInputIronOxides: function(e) {
-    this.setData({
-      'newData.free_iron_oxides': e.detail.value
-    });
-  },
-  onInputinitPH: function(e) {
-    this.setData({
-      'newData.pH': e.detail.value
-    });
-  },
-  onInputfinalPH: function(e) {
-    this.setData({
-      'newData.final_pH': e.detail.value
-    });
-  },
-  onInputlocation: function(e) {
-    this.setData({
-      'newData.Collection_location': e.detail.value
-    });
-  },
-  onBindDateChange: function(e) {
-    this.setData({
-      'newData.Collection_date': e.detail.value
-    });
-  },
 
   // 提交新增数据
   onSubmitAdd: function() {
@@ -211,7 +375,7 @@ Page({
         'Content-Type': 'application/json'
       },
       data: {
-        table: 'Soil_samples',
+        table: 'current_reduce',
         item: newRow
       },
       success: (res) => {
@@ -291,7 +455,7 @@ onSubmitEdit: function() {
       'Content-Type': 'application/json'
     },
     data: {
-      table: 'Soil_samples',
+      table: 'current_reduce',
       item: updatedRow
     },
     success: (res) => {
@@ -330,17 +494,14 @@ onSubmitEdit: function() {
     const { index, row } = this.data.currentRow;
     console.log("当前选中行的数据:", this.data.currentRow);
   
-    const condition = `Sample_ID=${row.Sample_ID}`;  // 使用条件进行删除
+    const condition = `id=${row.id}`;  // 使用条件进行删除
   
     // 发送 DELETE 请求
     wx.request({
-      url: 'http://127.0.0.1:5000/delete_item',  // 确保使用正确的URL
-      method: 'DELETE',  // 使用 DELETE 请求方法
-      header: {
-        'Content-Type': 'application/json'  // 请求类型是 JSON
-      },
+      url: 'http://127.0.0.1:5000/delete_item',  // 后端接口地址
+      method: 'POST',  // 使用 POST 请求
       data: {
-        table: 'Soil_samples',  // 目标表
+        table: 'current_reduce',  // 目标表
         condition: condition  // 删除条件
       },
       success: (res) => {
@@ -356,7 +517,7 @@ onSubmitEdit: function() {
             title: '删除成功',
             icon: 'success'
           });
-  
+    
           // 重新获取数据
           this.LoadData();  // 重新加载数据
         } else {
@@ -374,7 +535,7 @@ onSubmitEdit: function() {
         console.error('请求失败:', err);
       }
     });
-  },  
+  }, 
 
   onSubmit: function() {
     if (this.data.isEditing) {
@@ -383,6 +544,7 @@ onSubmitEdit: function() {
       this.onSubmitAdd();
     }
   },
+
   // 取消编辑删除弹窗
   onCancel: function() {
     if (this.data.showModal) {

+ 30 - 37
pages/Visualizatio/Visualizatio.wxml

@@ -10,10 +10,10 @@
   </view>
 
   <view class="add-btn-container">
-  <button class="add-btn" bindtap="onAdd">新增</button>
   <button class="add-btn" bindtap="onImport">导入</button>
   <button class="add-btn" bindtap="onExport">导出</button>
-
+  <button class="add-btn" bindtap="onDownloadTemplate">下载模板</button>
+  <button class="add-btn" bindtap="onAdd">新增</button>
   </view>
 </view>
 
@@ -37,18 +37,12 @@
           <view class='item'>{{item}}</view>
         </view>
         <view class="table-cell">{{index + 1}}</view> <!-- 序号 -->
+        <view class="table-cell">{{item.Q_over_b}}</view>
         <view class="table-cell">{{item.pH}}</view>
         <view class="table-cell">{{item.OM}}</view>
         <view class="table-cell">{{item.CL}}</view>
-        <view class="table-cell">{{item.CEC}}</view>
         <view class="table-cell">{{item.H}}</view>
-        <view class="table-cell">{{item.HN}}</view>
         <view class="table-cell">{{item.Al}}</view>
-        <view class="table-cell">{{item.free_alumina}}</view>
-        <view class="table-cell">{{item.free_iron_oxides}}</view>
-        <view class="table-cell">{{item.final_pH}}</view>
-        <view class="table-cell">{{Collection_location}}</view>
-        <view class="table-cell">{{Collection_date}}</view>
       </view>
     </block>
   </view>
@@ -57,36 +51,35 @@
 <!-- 新增数据弹窗 -->
 <view class="modal" wx:if="{{showAddModal}}">
   <view class="modal-content">
-    <view class="page-section-title">0 day pH:</view>
-    <input class="input-field" placeholder="请输入0 day pH" data-field="pH" bindinput="onInputinitPH" value="{{newData.pH}}"/>
-    <view class="page-section-title">有机质含量 (OM g/kg):</view>
-    <input class="input-field" placeholder="请输入OM含量" data-field="OM" bindinput="onInputOM" value="{{newData.OM}}"/>
-    <view class="page-section-title">土壤粘粒重量 (CL g/kg):</view>
-    <input class="input-field" placeholder="请输入CL含量" data-field="CL" bindinput="onInputCL" value="{{newData.CL}}"/>
-    <view class="page-section-title">阳离子交换量 (CEC cmol/kg):</view>
-    <input class="input-field" placeholder="请输入CEC含量" data-field="CEC" bindinput="onInputCEC" value="{{newData.CEC}}"/>
-    <view class="page-section-title">氢离子含量 (H+ cmol/kg):</view>
-    <input class="input-field" placeholder="请输入H+含量" data-field="H" bindinput="onInputHplus" value="{{newData.H}}"/>
-    <view class="page-section-title">铵离子含量 (HN cmol/kg):</view>
-    <input class="input-field" placeholder="请输入HN含量" data-field="HN" bindinput="onInputHN" value="{{newData.HN}}"/>
-    <view class="page-section-title">铝离子含量 (Al3+ cmol/kg):</view>
-    <input class="input-field" placeholder="请输入Al3+含量" data-field="Al" bindinput="onInputAl3plus" value="{{newData.Al}}"/>
-    <view class="page-section-title">游离氧化铝 (free alumina g/kg):</view>
-    <input class="input-field" placeholder="请输入游离氧化铝含量" data-field="free_alumina" bindinput="onInputAlumina" value="{{newData.free_alumina}}"/>
-    <view class="page-section-title">游离氧化铁 (free iron oxides g/kg):</view>
-    <input class="input-field" placeholder="请输入游离氧化铁含量" data-field="free_iron_oxides" bindinput="onInputIronOxides"value="{{newData.free_iron_oxides}}" />
-    <view class="page-section-title">105 day pH:</view>
-    <input class="input-field" placeholder="请输入105 day pH" data-field="final_pH" bindinput="onInputfinalPH"value="{{newData.final_pH}}" />
-    <view class="page-section-title">采样地点: </view>
-<input class="input-field" placeholder="请输入采样地点" data-field="collection_location" bindinput="onInputlocation" value="{{newData.Collection_location}}"/>
 
-<!-- 日期选择器 -->
-<picker mode="date" value="{{newData.Collection_date}}" bindchange="onBindDateChange">
-  <view class="picker-container">
-    <text class="page-section-title">采样时间:</text>
-    <text class="color6">{{newData.Collection_date || '请选择日期'}}</text>
+    <view class="modal-item">
+    <view class="item-label">比值:</view>
+    <input class="input-field" placeholder="比值" data-field="Q_over_b" bindinput="onInputQ_over_b" value="{{newData.Q_over_b}}"/>
+  </view>
+    <view class="modal-item">
+    <view class="item-label">酸碱度:</view>
+    <input class="input-field" placeholder="请输入酸碱度" data-field="pH" bindinput="onInputpH" value="{{newData.pH}}"/>
+  </view>
+
+    <view class="modal-item">
+    <view class="item-label">有机质含量:</view>
+    <input class="input-field" placeholder="请输入有机质含量" data-field="OM" bindinput="onInputOM" value="{{newData.OM}}"/>
+  </view>
+
+    <view class="modal-item">
+    <view class="item-label">氯离子含量:</view>
+    <input class="input-field" placeholder="请输入氯离子含量" data-field="CL" bindinput="onInputCL" value="{{newData.CL}}"/>
+  </view>
+
+    <view class="modal-item">
+    <view class="item-label">氢离子含量:</view>
+    <input class="input-field" placeholder="请输入H含量" data-field="H" bindinput="onInputH" value="{{newData.H}}"/>
+  </view>
+
+    <view class="modal-item">
+    <view class="item-label">铝离子含量:</view>
+    <input class="input-field" placeholder="请输入铝离子含量" data-field="Al" bindinput="onInputAl" value="{{newData.Al}}"/>
   </view>
-    </picker>
 
     <view class="button-container">
       <button class="submit-btn" bindtap="onSubmit">确认</button>

+ 48 - 50
pages/Visualizatio/Visualizatio.wxss

@@ -132,69 +132,41 @@
   max-height: 80vh; /* 最大高度,留出一些空间以便滚动条显示 */
   overflow-y: auto; /* 垂直方向溢出时显示滚动条 */
   overflow-x: hidden; /* 隐藏水平滚动条 */
+  display: flex;
+  flex-direction: column; /* 默认垂直方向布局 */
+  align-items: flex-start; /* 左对齐 */
 }
 
-/* 每个选项项 */
+/* 每个输入项 */
 .modal-item {
-  text-align: center; /* 每个项的文本居中 */
-  font-size: 32rpx; /* 字体大小 */
-  padding: 20rpx 0; /* 内边距 */
-  border-top: 1rpx solid #eee; /* 上边框为浅灰色 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.2s; /* 添加鼠标悬停的平滑过渡 */
-}
-
-/* 第一项不显示上边框 */
-.modal-item:first-child {
-  border-top: none;
-}
-
-/* 提交按钮样式 */
-.submit-btn {
-  background-color: #4CAF50; /* 绿色背景 */
-  color: white; /* 白色字体 */
-  border: none; /* 去掉边框 */
-  padding: 10rpx 20rpx; /* 内边距 */
-  font-size: 32rpx; /* 字体大小 */
-  border-radius: 8rpx; /* 圆角 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.3s ease; /* 背景色变化平滑过渡 */
-}
-
-/* 提交按钮悬停效果 */
-.submit-btn:hover {
-  background-color: #45a049; /* 悬停时变为更深的绿色 */
-}
-
-/* 取消按钮样式 */
-.cancel-btn {
-  background-color: #e74c3c; /* 红色背景 */
-  color: white; /* 白色字体 */
-  border: none; /* 去掉边框 */
-  padding: 10rpx 20rpx; /* 内边距 */
-  font-size: 32rpx; /* 字体大小 */
-  border-radius: 8rpx; /* 圆角 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.3s ease; /* 背景色变化平滑过渡 */
+  display: flex; /* 使用 flex 布局 */
+  align-items: center; /* 垂直居中 */
+  width: 100%;
+  margin-bottom: 15rpx; /* 每个输入项之间的间隔 */
 }
 
-/* 取消按钮悬停效果 */
-.cancel-btn:hover {
-  background-color: #c0392b; /* 悬停时变为更深的红色 */
+/* 输入框标签 */
+.item-label {
+  width: 30%; /* 标签宽度 */
+  font-size: 16px;
+  margin-right: 15rpx; /* 标签与输入框之间的间隔 */
+  text-align: right; /* 标签文本右对齐 */
 }
 
-/* 新增数据弹窗的按钮容器 */
-.modal-content {
-  display: flex;
-  flex-direction: column; /* 默认垂直方向布局 */
-  align-items: center; /* 居中对齐内容 */
+/* 输入框样式 */
+.input-field {
+  flex: 1; /* 输入框占据剩余空间 */
+  padding: 8px;
+  font-size: 16px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
 }
 
 /* 按钮容器 */
 .button-container {
   display: flex; /* 使用 flexbox 布局 */
   justify-content: space-between; /* 按钮之间均匀分布 */
-  width: 100%; /* 按钮容器宽度为 100% */
+  width: 100%;
   margin-top: 20rpx; /* 上边距 */
 }
 
@@ -202,4 +174,30 @@
 .submit-btn, .cancel-btn {
   flex: 1; /* 使按钮宽度相等 */
   margin: 0 10rpx; /* 按钮间隔 */
+  padding: 10px;
+  border-radius: 5px;
+  font-size: 16px;
+  cursor: pointer;
+}
+
+/* 提交按钮样式 */
+.submit-btn {
+  background-color: #4CAF50; /* 绿色背景 */
+  color: white;
+}
+
+/* 取消按钮样式 */
+.cancel-btn {
+  background-color: #e74c3c; /* 红色背景 */
+  color: white;
+}
+
+/* 提交按钮悬停效果 */
+.submit-btn:hover {
+  background-color: #45a049;
+}
+
+/* 取消按钮悬停效果 */
+.cancel-btn:hover {
+  background-color: #c0392b;
 }

+ 250 - 64
pages/Visualization/Visualization.js

@@ -1,6 +1,8 @@
 Page({
   data: {
     isEditing: false,
+    tableName: 'current_reflux', // 确保这个表名在页面中是有效的
+    fileFormat: 'excel', // 默认是 Excel 格式
     shoopingtext: "", // 搜索框内容
     filteredRows: [], // 表格过滤后的数据
     rows: [], // 所有表格数据
@@ -9,25 +11,21 @@ Page({
     currentRow: null, // 当前选中的表格行
     // 新增数据弹窗的输入框内容
     newData: {
-      Sample_ID: "",
+      id: "",
       OM: "",
       CL: "",
       CEC: "",
-      H: "",
+      H_plus: "",
       HN: "",
-      Al: "",
+      Al3_plus: "",
       free_alumina: "",
       free_iron_oxides: "",
-      pH: "",
-      final_pH: "",
-      Collection_location: "",
-      Collection_date: ""
+      Delta_pH: ""
     },
     // 中文表头内容,动态生成
     tableHeaders: [
-      "序号", "0天 pH", "有机质含量 (g/kg)", "土壤粘粒重量 (g/kg)", "阳离子交换量 (cmol/kg)", 
-      "氢离子含量 (cmol/kg)", "铵离子含量 (mg/kg)", "铝离子含量 (cmol/kg)", "游离氧化铝 (g/kg)", 
-      "游离氧化铁 (g/kg)", "105天 pH", "采集位置", "采集日期"
+      "序号", "有机质含量", "土壤粘粒重量", "阳离子交换量", "氢离子含量",
+      "硝态氮含量","铝离子含量", "游离氧化铝", "游离氧化铁", "酸碱差值",
     ]
   },
 
@@ -44,7 +42,7 @@ Page({
         'Content-Type': 'application/json'
       },
       data: {
-        table: 'Soil_samples'
+        table: 'current_reflux'
     },
     success: (res) => {
       console.log('后端返回数据:', res.data.rows); // 打印返回数据,确认格式
@@ -52,19 +50,16 @@ Page({
       if (res.data && Array.isArray(res.data.rows)) {
         const rows = res.data.rows.map(row => {
           return {
-            'Sample_ID': row[0],
-            'pH': row[1],
-            'OM': row[2],
-            'CL': row[3],
-            'CEC': row[4],
-            'H': row[5],
-            'HN': row[6],
-            'Al': row[7],
-            'free_alumina': row[8],
-            'free_iron_oxides': row[9],
-            'final_pH': row[10],
-            'Collection_location': row[11],
-            'Collection_date': row[12]
+            'id': row[0],
+            'OM': row[1],
+            'CL': row[2],
+            'CEC': row[3],
+            'H_plus': row[4],
+            'HN': row[5],
+            'Al3_plus': row[6],
+            'free_alumina': row[7],
+            'free_iron_oxides': row[8],
+            'Delta_pH': row[9],
           };
         });
 
@@ -108,6 +103,217 @@ Page({
     });
   },
 
+ // 下载模板函数
+ onDownloadTemplate: function() {
+  wx.showLoading({
+    title: '下载中...',
+  });
+
+  const tableName = 'current_reflux';  // 或者根据需要选择表名
+  const format = 'excel';  // 或者 'csv' 作为模板格式
+
+  wx.request({
+    url: `http://localhost:5000/download_template?table=${tableName}&format=${format}`,
+    method: 'GET',
+    responseType: 'arraybuffer',  // 处理二进制文件
+    success: (res) => {
+      wx.hideLoading();
+
+      // 确保响应体返回的数据是有效的文件
+      if (res.statusCode === 200) {
+        const fileType = format === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'text/csv';
+
+        // 生成唯一的文件名,添加时间戳以确保唯一性
+        const timestamp = new Date().getTime();
+        const fileName = `${tableName}_template_${timestamp}.${format}`;
+        const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
+
+        // 使用文件系统管理器保存文件
+        const fs = wx.getFileSystemManager();
+        fs.writeFile({
+          filePath: filePath,
+          data: res.data,
+          encoding: 'binary',
+          success: () => {
+            wx.showToast({
+              title: '文件已保存',
+              icon: 'success'
+            });
+            // 触发文件下载
+            wx.openDocument({
+              filePath: filePath,
+              fileType: format === 'excel' ? 'xlsx' : 'csv',
+              success: () => {
+                console.log('文件打开成功');
+              },
+              fail: (error) => {
+                console.error('文件打开失败', error);
+                wx.showToast({
+                  title: '打开文件失败',
+                  icon: 'none'
+                });
+              }
+            });
+          },
+          fail: (err) => {
+            wx.showToast({
+              title: '文件保存失败',
+              icon: 'none'
+            });
+            console.error('文件保存失败', err);
+          }
+        });
+      } else {
+        wx.showToast({
+          title: '下载失败',
+          icon: 'none'
+        });
+      }
+    },
+    fail: (err) => {
+      wx.hideLoading();
+      wx.showToast({
+        title: '请求失败,请重试',
+        icon: 'none'
+      });
+      console.error('请求失败:', err);
+    }
+  });
+},  
+
+   // 导出数据按钮点击事件
+   onExport: function () {
+    const tableName = this.data.tableName;
+    const fileFormat = this.data.fileFormat;
+
+    wx.showLoading({
+      title: '导出中...',
+    });
+
+    // 向后端发送请求,获取表格数据并导出
+    wx.request({
+      url: `http://localhost:5000/export_data?table=${tableName}&format=${fileFormat}`,
+      method: 'GET',
+      responseType: 'arraybuffer',  // 处理二进制文件
+      success: (res) => {
+        wx.hideLoading();
+
+        // 确保响应体返回的数据是有效的文件
+        if (res.statusCode === 200) {
+          const fileName = `${tableName}_data.${fileFormat === 'excel' ? 'xlsx' : 'csv'}`;
+          const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
+
+          // 保存文件到本地
+          wx.getFileSystemManager().writeFile({
+            filePath: filePath,
+            data: res.data,
+            encoding: 'binary',
+            success: () => {
+              wx.showToast({
+                title: '文件已保存',
+                icon: 'success'
+              });
+
+              // 打开已保存的文件
+              wx.openDocument({
+                filePath: filePath,
+                fileType: fileFormat === 'excel' ? 'xlsx' : 'csv',
+                success: () => {
+                  console.log('文件打开成功');
+                },
+                fail: (error) => {
+                  console.error('文件打开失败', error);
+                  wx.showToast({
+                    title: '打开文件失败',
+                    icon: 'none'
+                  });
+                }
+              });
+            },
+            fail: (err) => {
+              wx.showToast({
+                title: '文件保存失败',
+                icon: 'none'
+              });
+              console.error('文件保存失败', err);
+            }
+          });
+        } else {
+          wx.showToast({
+            title: '导出失败,请重试',
+            icon: 'none'
+          });
+        }
+      },
+      fail: (err) => {
+        wx.hideLoading();
+        wx.showToast({
+          title: '请求失败,请重试',
+          icon: 'none'
+        });
+        console.error('请求失败:', err);
+      }
+    });
+  },
+
+  // 导入数据功能
+  onImport: function () {
+    wx.chooseMessageFile({
+      count: 1,
+      type: 'file',
+      extension: ['xlsx', 'csv'], // 允许上传的文件类型
+      success: (res) => {
+        const filePath = res.tempFiles[0].path; // 获取文件临时路径
+        const fileName = res.tempFiles[0].name;
+
+        wx.showLoading({
+          title: '上传中...',
+        });
+
+        // 上传文件到后端
+        wx.uploadFile({
+          url: 'http://localhost:5000/import_data', // 后端处理导入的接口
+          filePath: filePath,
+          name: 'file',
+          formData: {
+            table: this.data.tableName, // 表名,后端根据需要解析数据
+            fileName: fileName
+          },
+          success: (res) => {
+            wx.hideLoading();
+            const responseData = JSON.parse(res.data);
+
+            if (responseData.success) {
+              wx.showToast({
+                title: '导入成功',
+                icon: 'success'
+              });
+
+              // 重新加载数据
+              this.LoadData();
+            } else {
+              wx.showToast({
+                title: '导入失败,请检查文件格式',
+                icon: 'none'
+              });
+            }
+          },
+          fail: (err) => {
+            wx.hideLoading();
+            wx.showToast({
+              title: '导入失败,请重试',
+              icon: 'none'
+            });
+            console.error('文件上传失败:', err);
+          }
+        });
+      },
+      fail: (err) => {
+        console.error('文件选择失败:', err);
+      }
+    });
+  },
+
   // 新增按钮点击,显示新增弹窗
   onAdd: function() {
     console.log("新增按钮被点击了");  // 调试日志
@@ -117,15 +323,12 @@ Page({
         OM: "",
         CL: "",
         CEC: "",
-        H: "",
+        H_plus: "",
         HN: "",
-        Al: "",
+        Al3_plus: "",
         free_alumina: "",
         free_iron_oxides: "",
-        pH: "",
-        final_pH: "",
-        Collection_location: "",
-        Collection_date: ""
+        Delta_pH: ""
       }
     });
     console.log("showAddModal: ", this.data.showAddModal);  // 确认数据更新
@@ -147,9 +350,9 @@ Page({
       'newData.CEC': e.detail.value
     });
   },
-  onInputHplus: function(e) {
+  onInputH_plus: function(e) {
     this.setData({
-      'newData.H': e.detail.value
+      'newData.H_plus': e.detail.value
     });
   },
   onInputHN: function(e) {
@@ -157,39 +360,24 @@ Page({
       'newData.HN': e.detail.value
     });
   },
-  onInputAl3plus: function(e) {
+  onInputAl3_plus: function(e) {
     this.setData({
-      'newData.Al': e.detail.value
+      'newData.Al3_plus': e.detail.value
     });
   },
-  onInputAlumina: function(e) {
+  onInputfree_alumina: function(e) {
     this.setData({
       'newData.free_alumina': e.detail.value
     });
   },
-  onInputIronOxides: function(e) {
+  onInputfree_iron_oxides: function(e) {
     this.setData({
       'newData.free_iron_oxides': e.detail.value
     });
   },
-  onInputinitPH: function(e) {
+  onInputDelta_pH: function(e) {
     this.setData({
-      'newData.pH': e.detail.value
-    });
-  },
-  onInputfinalPH: function(e) {
-    this.setData({
-      'newData.final_pH': e.detail.value
-    });
-  },
-  onInputlocation: function(e) {
-    this.setData({
-      'newData.Collection_location': e.detail.value
-    });
-  },
-  onBindDateChange: function(e) {
-    this.setData({
-      'newData.Collection_date': e.detail.value
+      'newData.Delta_pH': e.detail.value
     });
   },
 
@@ -211,7 +399,7 @@ Page({
         'Content-Type': 'application/json'
       },
       data: {
-        table: 'Soil_samples',
+        table: 'current_reflux',
         item: newRow
       },
       success: (res) => {
@@ -291,7 +479,7 @@ onSubmitEdit: function() {
       'Content-Type': 'application/json'
     },
     data: {
-      table: 'Soil_samples',
+      table: 'current_reflux',
       item: updatedRow
     },
     success: (res) => {
@@ -330,17 +518,14 @@ onSubmitEdit: function() {
     const { index, row } = this.data.currentRow;
     console.log("当前选中行的数据:", this.data.currentRow);
   
-    const condition = `Sample_ID=${row.Sample_ID}`;  // 使用条件进行删除
+    const condition = `id=${row.id}`;  // 使用条件进行删除
   
     // 发送 DELETE 请求
     wx.request({
-      url: 'http://127.0.0.1:5000/delete_item',  // 确保使用正确的URL
-      method: 'DELETE',  // 使用 DELETE 请求方法
-      header: {
-        'Content-Type': 'application/json'  // 请求类型是 JSON
-      },
+      url: 'http://127.0.0.1:5000/delete_item',  // 后端接口地址
+      method: 'POST',  // 使用 POST 请求
       data: {
-        table: 'Soil_samples',  // 目标表
+        table: 'current_reflux',  // 目标表
         condition: condition  // 删除条件
       },
       success: (res) => {
@@ -356,7 +541,7 @@ onSubmitEdit: function() {
             title: '删除成功',
             icon: 'success'
           });
-  
+    
           // 重新获取数据
           this.LoadData();  // 重新加载数据
         } else {
@@ -374,7 +559,7 @@ onSubmitEdit: function() {
         console.error('请求失败:', err);
       }
     });
-  },  
+  }, 
 
   onSubmit: function() {
     if (this.data.isEditing) {
@@ -383,6 +568,7 @@ onSubmitEdit: function() {
       this.onSubmitAdd();
     }
   },
+
   // 取消编辑删除弹窗
   onCancel: function() {
     if (this.data.showModal) {

+ 61 - 38
pages/Visualization/Visualization.wxml

@@ -10,10 +10,10 @@
   </view>
 
   <view class="add-btn-container">
-  <button class="add-btn" bindtap="onAdd">新增</button>
   <button class="add-btn" bindtap="onImport">导入</button>
   <button class="add-btn" bindtap="onExport">导出</button>
-
+  <button class="add-btn" bindtap="onDownloadTemplate">下载模板</button>
+  <button class="add-btn" bindtap="onAdd">新增</button>
   </view>
 </view>
 
@@ -37,18 +37,15 @@
           <view class='item'>{{item}}</view>
         </view>
         <view class="table-cell">{{index + 1}}</view> <!-- 序号 -->
-        <view class="table-cell">{{item.pH}}</view>
         <view class="table-cell">{{item.OM}}</view>
         <view class="table-cell">{{item.CL}}</view>
         <view class="table-cell">{{item.CEC}}</view>
-        <view class="table-cell">{{item.H}}</view>
+        <view class="table-cell">{{item.H_plus}}</view>
         <view class="table-cell">{{item.HN}}</view>
-        <view class="table-cell">{{item.Al}}</view>
+        <view class="table-cell">{{item.Al3_plus}}</view>
         <view class="table-cell">{{item.free_alumina}}</view>
         <view class="table-cell">{{item.free_iron_oxides}}</view>
-        <view class="table-cell">{{item.final_pH}}</view>
-        <view class="table-cell">{{Collection_location}}</view>
-        <view class="table-cell">{{Collection_date}}</view>
+        <view class="table-cell">{{item.Delta_pH}}</view>
       </view>
     </block>
   </view>
@@ -57,37 +54,61 @@
 <!-- 新增数据弹窗 -->
 <view class="modal" wx:if="{{showAddModal}}">
   <view class="modal-content">
-    <view class="page-section-title">0 day pH:</view>
-    <input class="input-field" placeholder="请输入0 day pH" data-field="pH" bindinput="onInputinitPH" value="{{newData.pH}}"/>
-    <view class="page-section-title">有机质含量 (OM g/kg):</view>
-    <input class="input-field" placeholder="请输入OM含量" data-field="OM" bindinput="onInputOM" value="{{newData.OM}}"/>
-    <view class="page-section-title">土壤粘粒重量 (CL g/kg):</view>
-    <input class="input-field" placeholder="请输入CL含量" data-field="CL" bindinput="onInputCL" value="{{newData.CL}}"/>
-    <view class="page-section-title">阳离子交换量 (CEC cmol/kg):</view>
-    <input class="input-field" placeholder="请输入CEC含量" data-field="CEC" bindinput="onInputCEC" value="{{newData.CEC}}"/>
-    <view class="page-section-title">氢离子含量 (H+ cmol/kg):</view>
-    <input class="input-field" placeholder="请输入H+含量" data-field="H" bindinput="onInputHplus" value="{{newData.H}}"/>
-    <view class="page-section-title">铵离子含量 (HN cmol/kg):</view>
-    <input class="input-field" placeholder="请输入HN含量" data-field="HN" bindinput="onInputHN" value="{{newData.HN}}"/>
-    <view class="page-section-title">铝离子含量 (Al3+ cmol/kg):</view>
-    <input class="input-field" placeholder="请输入Al3+含量" data-field="Al" bindinput="onInputAl3plus" value="{{newData.Al}}"/>
-    <view class="page-section-title">游离氧化铝 (free alumina g/kg):</view>
-    <input class="input-field" placeholder="请输入游离氧化铝含量" data-field="free_alumina" bindinput="onInputAlumina" value="{{newData.free_alumina}}"/>
-    <view class="page-section-title">游离氧化铁 (free iron oxides g/kg):</view>
-    <input class="input-field" placeholder="请输入游离氧化铁含量" data-field="free_iron_oxides" bindinput="onInputIronOxides"value="{{newData.free_iron_oxides}}" />
-    <view class="page-section-title">105 day pH:</view>
-    <input class="input-field" placeholder="请输入105 day pH" data-field="final_pH" bindinput="onInputfinalPH"value="{{newData.final_pH}}" />
-    <view class="page-section-title">采样地点: </view>
-<input class="input-field" placeholder="请输入采样地点" data-field="collection_location" bindinput="onInputlocation" value="{{newData.Collection_location}}"/>
-
-<!-- 日期选择器 -->
-<picker mode="date" value="{{newData.Collection_date}}" bindchange="onBindDateChange">
-  <view class="picker-container">
-    <text class="page-section-title">采样时间:</text>
-    <text class="color6">{{newData.Collection_date || '请选择日期'}}</text>
-  </view>
-    </picker>
+    <!-- 有机质含量 -->
+    <view class="modal-item">
+      <text class="item-label">有机质含量:</text>
+      <input class="input-field" placeholder="请输入有机质含量" data-field="OM" bindinput="onInputOM" value="{{newData.OM}}"/>
+    </view>
+
+    <!-- 土壤粘粒重量 -->
+    <view class="modal-item">
+      <text class="item-label">土壤粘粒重量:</text>
+      <input class="input-field" placeholder="请输入土壤粘粒重量" data-field="CL" bindinput="onInputCL" value="{{newData.CL}}"/>
+    </view>
+
+    <!-- 阳离子交换量 -->
+    <view class="modal-item">
+      <text class="item-label">阳离子交换量:</text>
+      <input class="input-field" placeholder="请输入阳离子含量" data-field="CEC" bindinput="onInputCEC" value="{{newData.CEC}}"/>
+    </view>
 
+    <!-- 氢离子含量 -->
+    <view class="modal-item">
+      <text class="item-label">氢离子含量:</text>
+      <input class="input-field" placeholder="请输入氢离子含量" data-field="H_plus" bindinput="onInputH_plus" value="{{newData.H_plus}}"/>
+    </view>
+
+    <!-- 硝态氮含量 -->
+    <view class="modal-item">
+      <text class="item-label">硝态氮含量:</text>
+      <input class="input-field" placeholder="请输入硝态氮含量" data-field="HN" bindinput="onInputHN" value="{{newData.HN}}"/>
+    </view>
+
+    <!-- 铝离子含量 -->
+    <view class="modal-item">
+      <text class="item-label">铝离子含量:</text>
+      <input class="input-field" placeholder="请输入铝离子含量" data-field="Al3_plus" bindinput="onInputAl3_plus" value="{{newData.Al3_plus}}"/>
+    </view>
+
+    <!-- 游离氧化铝 -->
+    <view class="modal-item">
+      <text class="item-label">游离氧化铝:</text>
+      <input class="input-field" placeholder="请输入游离氧化铝含量" data-field="free_alumina" bindinput="onInputfree_alumina" value="{{newData.free_alumina}}"/>
+    </view>
+
+    <!-- 游离氧化铁 -->
+    <view class="modal-item">
+      <text class="item-label">游离氧化铁:</text>
+      <input class="input-field" placeholder="请输入游离氧化铁含量" data-field="free_iron_oxides" bindinput="onInputfree_iron_oxides" value="{{newData.free_iron_oxides}}"/>
+    </view>
+
+    <!-- 酸碱差值 -->
+    <view class="modal-item">
+      <text class="item-label">酸碱差值:</text>
+      <input class="input-field" placeholder="请输入酸碱差值" data-field="Delta_pH" bindinput="onInputDelta_pH" value="{{newData.Delta_pH}}"/>
+    </view>
+
+    <!-- 按钮容器 -->
     <view class="button-container">
       <button class="submit-btn" bindtap="onSubmit">确认</button>
       <button class="cancel-btn" bindtap="onCancel">取消</button>
@@ -95,6 +116,7 @@
   </view>
 </view>
 
+
 <!-- 底部编辑删除弹窗 -->
 <view class="modal" wx:if="{{showModal}}">
   <view class="modal-content">
@@ -103,3 +125,4 @@
     <view class="modal-item cancel" bindtap="onCancel">取消</view>
   </view>
 </view>
+

+ 48 - 50
pages/Visualization/Visualization.wxss

@@ -132,69 +132,41 @@
   max-height: 80vh; /* 最大高度,留出一些空间以便滚动条显示 */
   overflow-y: auto; /* 垂直方向溢出时显示滚动条 */
   overflow-x: hidden; /* 隐藏水平滚动条 */
+  display: flex;
+  flex-direction: column; /* 默认垂直方向布局 */
+  align-items: flex-start; /* 左对齐 */
 }
 
-/* 每个选项项 */
+/* 每个输入项 */
 .modal-item {
-  text-align: center; /* 每个项的文本居中 */
-  font-size: 32rpx; /* 字体大小 */
-  padding: 20rpx 0; /* 内边距 */
-  border-top: 1rpx solid #eee; /* 上边框为浅灰色 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.2s; /* 添加鼠标悬停的平滑过渡 */
-}
-
-/* 第一项不显示上边框 */
-.modal-item:first-child {
-  border-top: none;
-}
-
-/* 提交按钮样式 */
-.submit-btn {
-  background-color: #4CAF50; /* 绿色背景 */
-  color: white; /* 白色字体 */
-  border: none; /* 去掉边框 */
-  padding: 10rpx 20rpx; /* 内边距 */
-  font-size: 32rpx; /* 字体大小 */
-  border-radius: 8rpx; /* 圆角 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.3s ease; /* 背景色变化平滑过渡 */
-}
-
-/* 提交按钮悬停效果 */
-.submit-btn:hover {
-  background-color: #45a049; /* 悬停时变为更深的绿色 */
-}
-
-/* 取消按钮样式 */
-.cancel-btn {
-  background-color: #e74c3c; /* 红色背景 */
-  color: white; /* 白色字体 */
-  border: none; /* 去掉边框 */
-  padding: 10rpx 20rpx; /* 内边距 */
-  font-size: 32rpx; /* 字体大小 */
-  border-radius: 8rpx; /* 圆角 */
-  cursor: pointer; /* 鼠标悬停时显示为手指 */
-  transition: background-color 0.3s ease; /* 背景色变化平滑过渡 */
+  display: flex; /* 使用 flex 布局 */
+  align-items: center; /* 垂直居中 */
+  width: 100%;
+  margin-bottom: 15rpx; /* 每个输入项之间的间隔 */
 }
 
-/* 取消按钮悬停效果 */
-.cancel-btn:hover {
-  background-color: #c0392b; /* 悬停时变为更深的红色 */
+/* 输入框标签 */
+.item-label {
+  width: 30%; /* 标签宽度 */
+  font-size: 16px;
+  margin-right: 15rpx; /* 标签与输入框之间的间隔 */
+  text-align: right; /* 标签文本右对齐 */
 }
 
-/* 新增数据弹窗的按钮容器 */
-.modal-content {
-  display: flex;
-  flex-direction: column; /* 默认垂直方向布局 */
-  align-items: center; /* 居中对齐内容 */
+/* 输入框样式 */
+.input-field {
+  flex: 1; /* 输入框占据剩余空间 */
+  padding: 8px;
+  font-size: 16px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
 }
 
 /* 按钮容器 */
 .button-container {
   display: flex; /* 使用 flexbox 布局 */
   justify-content: space-between; /* 按钮之间均匀分布 */
-  width: 100%; /* 按钮容器宽度为 100% */
+  width: 100%;
   margin-top: 20rpx; /* 上边距 */
 }
 
@@ -202,4 +174,30 @@
 .submit-btn, .cancel-btn {
   flex: 1; /* 使按钮宽度相等 */
   margin: 0 10rpx; /* 按钮间隔 */
+  padding: 10px;
+  border-radius: 5px;
+  font-size: 16px;
+  cursor: pointer;
+}
+
+/* 提交按钮样式 */
+.submit-btn {
+  background-color: #4CAF50; /* 绿色背景 */
+  color: white;
+}
+
+/* 取消按钮样式 */
+.cancel-btn {
+  background-color: #e74c3c; /* 红色背景 */
+  color: white;
+}
+
+/* 提交按钮悬停效果 */
+.submit-btn:hover {
+  background-color: #45a049;
+}
+
+/* 取消按钮悬停效果 */
+.cancel-btn:hover {
+  background-color: #c0392b;
 }

+ 34 - 214
pages/admin/admin.js

@@ -1,181 +1,41 @@
 Page({
   data: {
-    isLogin: false, // 登录状态
-    isHidden: true, // 弹窗状态
-    avatarUrl: '', // 用户头像
-    nickName: '', // 用户昵称
-    username: '', // 用户名(用户名密码登录)
-    password: '', // 密码(用户名密码登录)
-    errorMessage: '', // 错误信息
+    selected: 3,     // 底部导航栏选中的 tab
+    username: '',     // 用户名
+    password: '',     // 密码
+    errorMessage: ''   // 错误信息
   },
 
-  // 获取用户头像
-  getAvatar(e) {
-    const avatarUrl = e.detail.avatarUrl; // 从事件中获取头像URL
-
-    if (avatarUrl) {
-      this.setData({
-        avatarUrl: avatarUrl
-      });
-
-      // 创建userInfo对象,保存头像、昵称、用户名和密码到缓存
-      let userInfo = {
-        avatarUrl: avatarUrl,
-        nickName: this.data.nickName,
-        username: this.data.username, // 保存用户名
-        password: this.data.password  // 保存密码
-      };
-      wx.setStorageSync('userInfo', userInfo); // 保存到缓存
-    } else {
-      wx.showToast({
-        title: '头像获取失败',
-        icon: 'error',
-        duration: 2000
-      });
-    }
-  },
-
-  // 获取用户昵称
-  getName(e) {
-    const nickName = e.detail.value; // 获取昵称
-    this.setData({
-      nickName: nickName
-    });
-
-    // 更新缓存中的昵称
-    let userInfo = wx.getStorageSync('userInfo') || {};
-    userInfo.nickName = nickName;
-    wx.setStorageSync('userInfo', userInfo); // 更新缓存
-  },
-
-  // 显示登录弹窗
-  gologin() {
-    this.setData({
-      isHidden: false
-    });
-  },
-
-  // 取消登录弹窗
-  potNo() {
-    this.setData({
-      isHidden: true
-    });
-  },
-
-  // 确认登录弹窗
-  popYes() {
-    const { avatarUrl, nickName, username, password } = this.data;
-
-    // 检查头像、昵称、用户名和密码是否存在
-    if ((!avatarUrl || !nickName) && (!username || !password)) {
-      wx.showToast({
-        icon: 'error',
-        title: '请获取头像、昵称、用户名和密码',
-      });
-      return;
-    }
-
-    // 如果头像和昵称存在,保存到缓存
-    if (avatarUrl && nickName) {
-      this.setData({
-        isLogin: true,
-        isHidden: true,
-      });
-
-      // 创建/更新 userInfo 对象并存储到缓存
-      let userInfo = {
-        avatarUrl: avatarUrl,
-        nickName: nickName,
-        username: this.data.username, // 保存用户名
-        password: this.data.password, // 保存密码
-      };
-      wx.setStorageSync('userInfo', userInfo); // 更新缓存
-
-      // 登录成功后跳转到指定页面
-      wx.navigateTo({
-        url: '/pages/RoleSelectionPage/RoleSelectionPage',
-      });
-
-      return;
-    }
-
-    // 检查用户名和密码是否一致登录
-    const storedUserInfo = wx.getStorageSync('userInfo');
-    if (storedUserInfo) {
-      const storedUsername = storedUserInfo.username;
-      const storedPassword = storedUserInfo.password;
-
-      // 验证用户名和密码
-      if (username === storedUsername && password === storedPassword) {
-        wx.showToast({
-          title: '登录成功',
-          icon: 'success',
-          duration: 2000
-        });
-
-        this.setData({
-          isLogin: true,
-          errorMessage: '',
-        });
-
-        // 登录成功后跳转到指定页面
-        wx.navigateTo({
-          url: '/pages/RoleSelectionPage/RoleSelectionPage',
-        });
-      } else {
-        this.setData({
-          errorMessage: '用户名或密码错误'
-        });
-        wx.showToast({
-          title: '用户名或密码错误',
-          icon: 'none',
-          duration: 2000
-        });
-      }
-    }
-  },
-
-  Register() {
-    wx.navigateTo({
-      url: '/pages/Register/Register',
-    });
-  },
-
-  // 用户名密码登录
-  inputUsername(e) {
+  // 输入用户名
+  inputUsername: function (e) {
     this.setData({
       username: e.detail.value
     });
   },
 
-  inputPassword(e) {
+  // 输入密码
+  inputPassword: function (e) {
     this.setData({
       password: e.detail.value
     });
   },
 
-  // 登录验证
-  login() {
+  // 登录逻辑
+  login: function () {
     const { username, password } = this.data;
 
-    // 获取缓存的用户信息
-    const storedUserInfo = wx.getStorageSync('userInfo');
-
-    // 检查用户信息是否存在
-    if (!storedUserInfo) {
-      this.setData({
-        errorMessage: '没有找到用户信息,请先注册'
-      });
-      return;
-    }
-
-    const storedUsername = storedUserInfo.username;
-    const storedPassword = storedUserInfo.password;
+    // 从本地存储获取有效的用户名和密码
+    const validUsers = wx.getStorageSync('validUsers') || {
+      'admin': '123456',
+      '123': '123'
+    };
 
     // 检查用户名和密码是否为空
     if (!username || !password) {
-      this.setData({
-        errorMessage: '用户名和密码不能为空'
+      wx.showToast({
+        title: '用户名和密码不能为空',
+        icon: 'none',
+        duration: 2000
       });
       return;
     }
@@ -185,25 +45,19 @@ Page({
     });
 
     setTimeout(() => {
-      wx.hideLoading();
-
-      // 验证输入的用户名和密码与缓存中的是否一致
-      if (username === storedUsername && password === storedPassword) {
-        wx.showToast({
-          title: '登录成功',
-          icon: 'success',
-          duration: 2000
-        });
-        this.setData({
-          isLogin: true,
-          errorMessage: '',
-        });
-
-        // 登录成功后跳转到指定页面
-        wx.navigateTo({
-          url: '/pages/RoleSelectionPage/RoleSelectionPage',
+      // 检查用户名和密码是否匹配
+      if (validUsers[username] === password) {
+        wx.hideLoading();
+        
+        // 登录成功后,将当前用户名和密码缓存到本地
+        const updatedUsers = { ...validUsers, [username]: password }; // 仅更新当前登录的用户名
+        wx.setStorageSync('validUsers', updatedUsers); // 更新本地存储
+
+        wx.switchTab({ // 跳转到 tabBar 页面
+          url: '/pages/threshold/threshold'
         });
       } else {
+        wx.hideLoading();
         this.setData({
           errorMessage: '用户名或密码错误'
         });
@@ -216,44 +70,10 @@ Page({
     }, 1500);
   },
 
-  // 页面加载时,检查是否有缓存的用户信息
-  onLoad() {
-    const storedUserInfo = wx.getStorageSync('userInfo');
-
-    // 如果有缓存的用户信息,自动填充头像、昵称、用户名和密码
-    if (storedUserInfo) {
-      this.setData({
-        avatarUrl: storedUserInfo.avatarUrl || '/assets/taddar/授权管理.png', // 默认头像
-        nickName: storedUserInfo.nickName || '未登录', // 默认昵称
-        username: storedUserInfo.username || '', // 默认用户名
-        password: storedUserInfo.password || '', // 默认密码
-        isLogin: true, // 设置已登录状态
-      });
-    }
-
-    // 如果没有设置头像,使用默认头像
-    if (!this.data.avatarUrl) {
-      this.setData({
-        avatarUrl: '/assets/taddar/授权管理.png' // 默认头像
-      });
-    }
-
-    // 获取存储的用户角色
-    const storedUserRole = wx.getStorageSync('userRole');  // 获取缓存中的用户角色
-
-    // 根据角色跳转页面
-    if (storedUserRole) {
-      if (storedUserRole === 'admin') {
-        // 如果是管理员,跳转到管理员页面
-        wx.reLaunch({
-          url: '/pages/threshold/threshold', // 管理员页面路径
-        });
-      } else if (storedUserRole === 'regular') {
-        // 如果是普通用户,跳转到普通用户页面
-        wx.reLaunch({
-          url: '/shoping/Home/Home', // 普通用户页面路径
-        });
-      }
+  // 隐藏返回首页按钮
+  onShow: function() {
+    if (wx.canIUse('hideHomeButton')) {
+      wx.hideHomeButton();
     }
   }
 });

+ 3 - 1
pages/admin/admin.json

@@ -1,5 +1,7 @@
 {
-  "usingComponents": {},
+  "usingComponents": {
+    "nav-tabar": "/components/shoping-tabbar/index"
+  },
   "navigationBarTitleText": "登录",
   "navigationBarBackgroundColor": "#f8f8f8",  
   "navigationBarTextStyle": "black"  

+ 6 - 41
pages/admin/admin.wxml

@@ -1,44 +1,9 @@
 <view class="container">
-   <!-- 用户名密码登录 -->
-   <view >
-    <input class="input" bindinput="inputUsername" placeholder="请输入用户名" />
-    <input class="input" bindinput="inputPassword" placeholder="请输入密码" type="password" />
-    <button class="gologin" bindtap="login">登录</button>
-    <text class="error">{{errorMessage}}</text>
-      <view class="center-list">
-    <view class="center-list-item">
-      <text class="list-text" bindtap="Register">新用户注册</text>
-      <image class="navigat-arrow" src="/assets/taddar/right.png" />
-    </view>
-  </view>
-  </view>
-  <view class="container">
-<button bindtap="gologin">微信登录</button>
+  <input class="input" bindinput="inputUsername" placeholder="请输入用户名" />
+  <input class="input" bindinput="inputPassword" placeholder="请输入密码" type="password" />
+  <button class="btn" bindtap="login">登录</button>
+  <text class="error">{{errorMessage}}</text>
 </view>
 
-
-  <!-- 登录弹窗 -->
-  <view class="pop_root" hidden="{{isHidden}}">
-    <view class="pop_content">
-      <view class="pot_tip">授权登录弹窗</view>
-      
-      <!-- 获取头像 -->
-      <button class="pop_avatar" open-type="chooseAvatar" bindchooseavatar="getAvatar">
-        <image class="pop_img" wx:if="{{avatarUrl}}" src="{{avatarUrl}}" />
-        <view wx:else>获取头像</view>
-      </button>
-      
-      <!-- 获取昵称 -->
-      <input 
-    class="pop_name" 
-    type="nickname" 
-    bindblur="getName"
-    placeholder="获取昵称"/>
-      
-      <view class="pop_bot">
-        <view class="btn" bind:tap="potNo">取消</view>
-        <view class="btn1" bind:tap="popYes">确定</view>
-      </view>
-    </view>
-  </view>
-</view>
+<!-- 底部导航栏 -->
+<nav-tabar selected="{{selected}}"></nav-tabar>

+ 10 - 140
pages/admin/admin.wxss

@@ -18,17 +18,16 @@
 }
 
 .btn {
-  width: 100%;
-  height: 80rpx;
-  background-color: var(--primary-color, #1aad19);
-  color: #fff;
-  border: none;
-  border-radius: var(--border-radius, 10rpx);
-  text-align: center;
-  line-height: 45rpx;
-  font-size: 36rpx;
-  box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.1);  /* 添加阴影 */
-  transition: background-color 0.3s ease, box-shadow 0.3s ease;  /* 背景颜色和阴影过渡效果 */
+  width: 50%;            /* 按钮占满宽度 */
+  padding: 5px 0;        /* 按钮内边距,控制高度 */
+  margin: 5px 0;         /* 按钮间距 */
+  background-color: #3EC01E; /* 按钮背景颜色 */
+  color: white;           /* 按钮文字颜色 */
+  font-size: 18px;        /* 按钮文字大小 */
+  border: none;           /* 去除按钮边框 */
+  outline: none;          /* 去除焦点边框 */
+  text-align: center;     /* 文字居中 */
+  border-radius: 5px;     /* 圆角效果 */
 }
 
 .btn:active {
@@ -77,132 +76,3 @@
     height: 60rpx;
   }
 }
-
-/* pages/demo/demo.wxss */
-.root {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  flex-direction: column;
-}
-
-.touxiang {
-  width: 300rpx;
-  height: 300rpx;
-  border-radius: 50%;
-  margin-top: 30rpx;
-}
-
-.name {
-  margin-top: 30rpx;
-}
-
-/* 弹窗 */
-.pop_root {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  background: rgb(0, 0, 0, 0.6);
-  z-index: 1000;
-}
-
-.pop_content {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  background: white;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  border-radius: 30rpx 30rpx 0 0;
-}
-
-.pot_tip {
-  font-size: 48rpx;
-  margin-top: 30rpx;
-}
-
-.pop_avatar {
-  width: 200rpx;
-  height: 200rpx;
-  border-radius: 50%;
-  background: gainsboro;
-  font-size: 35rpx;
-  display: flex;
-  flex-direction: center;
-  align-items: center;
-  margin: 30rpx;
-  padding: 0;
-}
-
-.pop_img {
-  width: 100%;
-  height: 100%;
-}
-
-.pop_name {
-  width: 300rpx;
-  bottom: 1px solid gray;
-  border-radius: 25epx;
-  padding-left: 160rpx;
-  margin-bottom: 50rpx;
-}
-
-.pop_bot {
-  display: flex;
-  margin-bottom: 50rpx;
-
-}
-
-.btn {
-  width: 150rpx;
-  border: 1px solid gray;
-  border-radius: 20rpx;
-  text-align: center;
-  background: red;
-  color: white;
-}
-
-.btn1 {
-  width: 150rpx;
-  border: 1px solid gray;
-  border-radius: 20rpx;
-  text-align: center;
-  background: green;
-  color: white;
-  margin-left: 90rpx;
-}
-
-/* 列表项样式 */
-.center-list-item {
-  box-sizing: border-box;
-  flex-direction: row;
-  padding: 0 20rpx;
-  display: flex;
-  justify-content: center; /* 图片和文本水平居中 */
-  align-items: center;     /* 图片和文本垂直居中 */
-}
-
-.list-text {
-  height: 90rpx;
-  line-height: 90rpx;
-  font-size: 34rpx;
-  color: #555;
-  flex: 1;
-  text-align: left;  /* 使文字水平居中 */
-}
-
-.navigat-arrow {
-  width: 40rpx;  /* 设置箭头图片的宽度 */
-  height: 40rpx; /* 设置箭头图片的高度 */
-  margin-top: 10rpx;
-  margin-left: 100rpx; /* 设置箭头和文本之间的间距 */
-  object-fit: contain; /* 保证图片不被拉伸 */
-}
-
-.list-text:active {
-  color: #299A0C; /* 按下按钮时的颜色变化 */
-}

+ 5 - 0
pages/threshold/threshold.js

@@ -22,5 +22,10 @@ Page({
     wx.navigateTo({
       url: '/pages/thres/thres',
     });
+  },
+  modelTrain() {
+    wx.navigateTo({
+      url: '/pages/ModelTrain/ModelTrain',
+    })
   }
 });

+ 2 - 0
pages/threshold/threshold.wxml

@@ -2,4 +2,6 @@
   <button class="full-width-button" bindtap="Model_Selection">模型选择</button>
 
   <button class="full-width-button" bindtap="thres">阈值选择</button>
+
+  <button class="full-width-button" bindtap="modelTrain">模型训练</button>
 </view>