Visualization.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. Page({
  2. data: {
  3. isEditing: false,
  4. tableName: 'current_reflux', // 确保这个表名在页面中是有效的
  5. fileFormat: 'excel', // 默认是 Excel 格式
  6. shoopingtext: "", // 搜索框内容
  7. filteredRows: [], // 表格过滤后的数据
  8. rows: [], // 所有表格数据
  9. showModal: false, // 控制底部编辑删除弹窗的显示与否
  10. showAddModal: false, // 控制新增数据弹窗的显示与否
  11. currentRow: null, // 当前选中的表格行
  12. // 新增数据弹窗的输入框内容
  13. newData: {
  14. id: "",
  15. OM: "",
  16. CL: "",
  17. CEC: "",
  18. H_plus: "",
  19. N: "",
  20. Al3_plus: "",
  21. Delta_pH: ""
  22. },
  23. // 中文表头内容,动态生成
  24. tableHeaders: [
  25. "序号", "有机质含量", "土壤粘粒", "阳离子交换量", "交换性氢",
  26. "水解氮","交换性铝", "ΔpH",
  27. ],
  28. unit: [
  29. " ", "(g/kg)", "(g/kg)", "(cmol/kg)", "(cmol/kg)",
  30. "(g/kg)", "(cmol/kg)", " "
  31. ]
  32. },
  33. // 页面加载时获取表格数据
  34. onLoad: function() {
  35. this.LoadData();
  36. },
  37. LoadData: function() {
  38. wx.request({
  39. url: 'https://soilgd.com:5000/table',
  40. method: 'POST',
  41. header: {
  42. 'Content-Type': 'application/json'
  43. },
  44. data: {
  45. table: 'current_reflux'
  46. },
  47. success: (res) => {
  48. console.log('后端返回数据:', res.data.rows); // 打印返回数据,确认格式
  49. if (res.data && Array.isArray(res.data.rows)) {
  50. const rows = res.data.rows.map(row => {
  51. return {
  52. 'id': row.id,
  53. 'OM': parseFloat(row.OM).toFixed(2),
  54. 'CL': parseFloat(row.CL).toFixed(2),
  55. 'CEC': parseFloat(row.CEC).toFixed(2),
  56. 'H_plus': parseFloat(row.H_plus).toFixed(2),
  57. 'N': parseFloat(row.N).toFixed(2),
  58. 'Al3_plus': parseFloat(row.Al3_plus).toFixed(2),
  59. 'Delta_pH': parseFloat(row.Delta_pH).toFixed(2),
  60. };
  61. });
  62. this.setData({
  63. rows: rows,
  64. filteredRows: rows
  65. });
  66. } else {
  67. wx.showToast({
  68. title: '获取数据失败',
  69. icon: 'none'
  70. });
  71. }
  72. },
  73. fail: (err) => {
  74. wx.showToast({
  75. title: '请求失败,请重试',
  76. icon: 'none'
  77. });
  78. console.error('请求失败:', err);
  79. }
  80. });
  81. },
  82. // 下载模板函数
  83. onDownloadTemplate: function() {
  84. wx.showLoading({
  85. title: '下载中...',
  86. });
  87. const tableName = 'current_reflux'; // 或者根据需要选择表名
  88. const format = 'excel'; // 或者 'csv' 作为模板格式
  89. wx.request({
  90. url: `https://soilgd.com:5000/download_template?table=${tableName}&format=${format}`,
  91. method: 'GET',
  92. responseType: 'arraybuffer', // 处理二进制文件
  93. success: (res) => {
  94. wx.hideLoading();
  95. // 确保响应体返回的数据是有效的文件
  96. if (res.statusCode === 200) {
  97. const fileType = format === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'text/csv';
  98. // 生成唯一的文件名,添加时间戳以确保唯一性
  99. const timestamp = new Date().getTime();
  100. const fileName = `${tableName}_template_${timestamp}.${format}`;
  101. const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
  102. // 使用文件系统管理器保存文件
  103. const fs = wx.getFileSystemManager();
  104. fs.writeFile({
  105. filePath: filePath,
  106. data: res.data,
  107. encoding: 'binary',
  108. success: () => {
  109. wx.showToast({
  110. title: '文件已保存',
  111. icon: 'success'
  112. });
  113. // 触发文件下载
  114. wx.openDocument({
  115. filePath: filePath,
  116. fileType: format === 'excel' ? 'xlsx' : 'csv',
  117. success: () => {
  118. console.log('文件打开成功');
  119. },
  120. fail: (error) => {
  121. console.error('文件打开失败', error);
  122. wx.showToast({
  123. title: '打开文件失败',
  124. icon: 'none'
  125. });
  126. }
  127. });
  128. },
  129. fail: (err) => {
  130. wx.showToast({
  131. title: '文件保存失败',
  132. icon: 'none'
  133. });
  134. console.error('文件保存失败', err);
  135. }
  136. });
  137. } else {
  138. wx.showToast({
  139. title: '下载失败',
  140. icon: 'none'
  141. });
  142. }
  143. },
  144. fail: (err) => {
  145. wx.hideLoading();
  146. wx.showToast({
  147. title: '请求失败,请重试',
  148. icon: 'none'
  149. });
  150. console.error('请求失败:', err);
  151. }
  152. });
  153. },
  154. // 导出数据按钮点击事件
  155. onExport: function () {
  156. const tableName = this.data.tableName;
  157. const fileFormat = this.data.fileFormat;
  158. wx.showLoading({
  159. title: '导出中...',
  160. });
  161. // 向后端发送请求,获取表格数据并导出
  162. wx.request({
  163. url: `https://soilgd.com:5000/export_data?table=${tableName}&format=${fileFormat}`,
  164. method: 'GET',
  165. responseType: 'arraybuffer', // 处理二进制文件
  166. success: (res) => {
  167. wx.hideLoading();
  168. // 确保响应体返回的数据是有效的文件
  169. if (res.statusCode === 200) {
  170. const fileName = `${tableName}_data.${fileFormat === 'excel' ? 'xlsx' : 'csv'}`;
  171. const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
  172. // 保存文件到本地
  173. wx.getFileSystemManager().writeFile({
  174. filePath: filePath,
  175. data: res.data,
  176. encoding: 'binary',
  177. success: () => {
  178. wx.showToast({
  179. title: '文件已保存',
  180. icon: 'success'
  181. });
  182. // 打开已保存的文件
  183. wx.openDocument({
  184. filePath: filePath,
  185. fileType: fileFormat === 'excel' ? 'xlsx' : 'csv',
  186. success: () => {
  187. console.log('文件打开成功');
  188. },
  189. fail: (error) => {
  190. console.error('文件打开失败', error);
  191. wx.showToast({
  192. title: '打开文件失败',
  193. icon: 'none'
  194. });
  195. }
  196. });
  197. },
  198. fail: (err) => {
  199. wx.showToast({
  200. title: '文件保存失败',
  201. icon: 'none'
  202. });
  203. console.error('文件保存失败', err);
  204. }
  205. });
  206. } else {
  207. wx.showToast({
  208. title: '导出失败,请重试',
  209. icon: 'none'
  210. });
  211. }
  212. },
  213. fail: (err) => {
  214. wx.hideLoading();
  215. wx.showToast({
  216. title: '请求失败,请重试',
  217. icon: 'none'
  218. });
  219. console.error('请求失败:', err);
  220. }
  221. });
  222. },
  223. // 导入数据功能
  224. onImport: function () {
  225. wx.chooseMessageFile({
  226. count: 1,
  227. type: 'file',
  228. extension: ['xlsx', 'csv'], // 允许上传的文件类型
  229. success: (res) => {
  230. const filePath = res.tempFiles[0].path;
  231. const fileName = res.tempFiles[0].name;
  232. wx.showLoading({ title: '上传中...' });
  233. // 上传文件到后端
  234. wx.uploadFile({
  235. url: 'https://soilgd.com:5000/import_data', // 后端接口
  236. filePath: filePath,
  237. name: 'file',
  238. formData: {
  239. table: this.data.tableName, // 表名
  240. fileName: fileName
  241. },
  242. success: (res) => {
  243. wx.hideLoading();
  244. const responseData = JSON.parse(res.data);
  245. if (responseData.success) {
  246. // 获取后端返回的结果
  247. const { total_data, new_data, duplicate_data, duplicate_details } = responseData;
  248. // 显示导入结果
  249. wx.showModal({
  250. title: '导入结果',
  251. content: `总数据: ${total_data} 条\n新增: ${new_data} 条\n重复: ${duplicate_data} 条`,
  252. success: () => {
  253. // 如果有重复数据,跳转到重复数据详情页面
  254. if (duplicate_data > 0) {
  255. wx.navigateTo({
  256. url: '/pages/duplicateDetails/duplicateDetails', // 重复数据详情页面
  257. success: (page) => {
  258. // 将重复数据传递给详情页面
  259. page.setData({ duplicateDetails: duplicate_details });
  260. }
  261. });
  262. }
  263. }
  264. });
  265. // 重新加载数据
  266. this.LoadData();
  267. } else {
  268. wx.showToast({
  269. title: responseData.message || '导入失败,请检查文件格式',
  270. icon: 'none'
  271. });
  272. }
  273. },
  274. fail: (err) => {
  275. wx.hideLoading();
  276. wx.showToast({
  277. title: '导入失败,请重试',
  278. icon: 'none'
  279. });
  280. console.error('文件上传失败:', err);
  281. }
  282. });
  283. },
  284. fail: (err) => {
  285. console.error('文件选择失败:', err);
  286. }
  287. });
  288. },
  289. // 新增按钮点击,显示新增弹窗
  290. onAdd: function() {
  291. console.log("新增按钮被点击了"); // 调试日志
  292. this.setData({
  293. isEditing: false, // 这里设置为 false,表示新增操作而非编辑
  294. showAddModal: true, // 显示新增数据弹窗
  295. newData: { // 重置新增数据
  296. OM: "",
  297. CL: "",
  298. CEC: "",
  299. H_plus: "",
  300. N: "",
  301. Al3_plus: "",
  302. Delta_pH: ""
  303. }
  304. });
  305. console.log("showAddModal: ", this.data.showAddModal); // 确认数据更新
  306. },
  307. // 输入框绑定:更新新增数据的对应字段
  308. onInputOM: function(e) {
  309. const value = e.detail.value;
  310. const filteredValue = value.replace(/[^0-9.]/g, '');
  311. this.setData({
  312. 'newData.OM': filteredValue,
  313. });
  314. },
  315. onInputCL: function(e) {
  316. const value = e.detail.value;
  317. const filteredValue = value.replace(/[^0-9.]/g, '');
  318. this.setData({
  319. 'newData.CL': filteredValue,
  320. });
  321. },
  322. onInputCEC: function(e) {
  323. const value = e.detail.value;
  324. const filteredValue = value.replace(/[^0-9.]/g, '');
  325. this.setData({
  326. 'newData.CEC': filteredValue,
  327. });
  328. },
  329. onInputH_plus: function(e) {
  330. const value = e.detail.value;
  331. const filteredValue = value.replace(/[^0-9.]/g, '');
  332. this.setData({
  333. 'newData.H_plus': filteredValue,
  334. });
  335. },
  336. onInputN: function(e) {
  337. const value = e.detail.value;
  338. const filteredValue = value.replace(/[^0-9.]/g, '');
  339. this.setData({
  340. 'newData.N': filteredValue,
  341. });
  342. },
  343. onInputAl3_plus: function(e) {
  344. const value = e.detail.value;
  345. const filteredValue = value.replace(/[^0-9.]/g, '');
  346. this.setData({
  347. 'newData.Al3_plus': filteredValue,
  348. });
  349. },
  350. onInputDelta_pH: function(e) {
  351. const value = e.detail.value;
  352. const filteredValue = value.replace(/[^0-9.]/g, '');
  353. this.setData({
  354. 'newData.Delta_pH': filteredValue,
  355. });
  356. },
  357. // 提交新增数据
  358. onSubmitAdd: function() {
  359. const newRow = this.data.newData;
  360. if (Object.values(newRow).some(value => !value)) {
  361. wx.showToast({
  362. title: '所有字段都必须填写!',
  363. icon: 'none'
  364. });
  365. return;
  366. }
  367. // 在请求之前打印数据,确保发送的数据正确
  368. console.log('Sending data:', {
  369. table: 'current_reflux',
  370. item: newRow
  371. });
  372. wx.request({
  373. url: 'https://soilgd.com:5000/add_item',
  374. method: 'POST',
  375. header: {
  376. 'Content-Type': 'application/json'
  377. },
  378. data: {
  379. table: 'current_reflux',
  380. item: newRow
  381. },
  382. success: (res) => {
  383. // 判断返回的状态码,进行处理
  384. if (res.statusCode === 200 && res.data.success) {
  385. this.setData({
  386. rows: [...this.data.rows, newRow],
  387. showAddModal: false
  388. });
  389. wx.showToast({
  390. title: '新增成功',
  391. icon: 'success'
  392. });
  393. this.LoadData();
  394. } else if (res.statusCode === 409) {
  395. wx.showToast({
  396. title: '重复数据,已有相同的数据项存在。',
  397. icon: 'none'
  398. });
  399. } else {
  400. wx.showToast({
  401. title: '新增失败',
  402. icon: 'none'
  403. });
  404. }
  405. },
  406. fail: (err) => {
  407. wx.showToast({
  408. title: '请求失败,请重试',
  409. icon: 'none'
  410. });
  411. console.error('请求失败:', err);
  412. }
  413. });
  414. },
  415. // 取消新增数据
  416. onCancel: function() {
  417. this.setData({
  418. showAddModal: false
  419. });
  420. },
  421. // 编辑按钮点击
  422. onEdit: function(e) {
  423. const { index, row } = this.data.currentRow;
  424. console.log(row);
  425. // 检查 currentRow 是否有定义并且包含数据
  426. if (row) {
  427. this.setData({
  428. isEditing: true,
  429. showModal: false,
  430. showAddModal: true, // 显示编辑弹窗
  431. newData: row, // 将当前行的数据复制到 newData 中,以便在表单中显示
  432. currentRow: { index: index, row: row } // 保存当前行的信息,以便在提交时使用
  433. });
  434. } else {
  435. wx.showToast({
  436. title: '数据加载失败,请重试',
  437. icon: 'none'
  438. });
  439. }
  440. },
  441. // 提交编辑数据
  442. onSubmitEdit: function() {
  443. const updatedRow = this.data.newData;
  444. const { index } = this.data.currentRow;
  445. if (Object.values(updatedRow).some(value => !value)) {
  446. wx.showToast({
  447. title: '所有字段都必须填写!',
  448. icon: 'none'
  449. });
  450. return;
  451. }
  452. wx.request({
  453. url: 'https://soilgd.com:5000/update_item',
  454. method: 'PUT',
  455. header: {
  456. 'Content-Type': 'application/json'
  457. },
  458. data: {
  459. table: 'current_reflux',
  460. item: updatedRow
  461. },
  462. success: (res) => {
  463. if (res.data.success) {
  464. // 更新成功后,更新前端数据
  465. let rows = this.data.rows;
  466. rows[index] = updatedRow; // 用更新后的数据替换旧数据
  467. this.setData({
  468. rows: rows,
  469. showAddModal: false // 关闭编辑弹窗
  470. });
  471. wx.showToast({
  472. title: '编辑成功',
  473. icon: 'success'
  474. });
  475. this.LoadData();
  476. } else {
  477. wx.showToast({
  478. title: '编辑失败',
  479. icon: 'none'
  480. });
  481. }
  482. },
  483. fail: (err) => {
  484. wx.showToast({
  485. title: '请求失败,请重试',
  486. icon: 'none'
  487. });
  488. console.error('请求失败:', err);
  489. }
  490. });
  491. },
  492. // 删除按钮点击
  493. onDelete: function() {
  494. const { index, row } = this.data.currentRow;
  495. console.log("当前选中行的数据:", this.data.currentRow);
  496. const condition = `id=${row.id}`; // 使用条件进行删除
  497. // 发送 DELETE 请求
  498. wx.request({
  499. url: 'https://soilgd.com:5000/delete_item', // 后端接口地址
  500. method: 'POST', // 使用 POST 请求
  501. data: {
  502. table: 'current_reflux', // 目标表
  503. condition: condition // 删除条件
  504. },
  505. success: (res) => {
  506. if (res.data.success) {
  507. // 删除成功后,更新前端数据
  508. let rows = this.data.rows;
  509. rows.splice(index, 1); // 从数据中删除选中的行
  510. this.setData({
  511. rows: rows,
  512. showModal: false // 隐藏编辑删除弹窗
  513. });
  514. wx.showToast({
  515. title: '删除成功',
  516. icon: 'success'
  517. });
  518. // 重新获取数据
  519. this.LoadData(); // 重新加载数据
  520. } else {
  521. wx.showToast({
  522. title: '删除失败',
  523. icon: 'none'
  524. });
  525. }
  526. },
  527. fail: (err) => {
  528. wx.showToast({
  529. title: '请求失败,请重试',
  530. icon: 'none'
  531. });
  532. console.error('请求失败:', err);
  533. }
  534. });
  535. },
  536. onSubmit: function() {
  537. if (this.data.isEditing) {
  538. this.onSubmitEdit();
  539. } else {
  540. this.onSubmitAdd();
  541. }
  542. },
  543. // 取消编辑删除弹窗
  544. onCancel: function() {
  545. if (this.data.showModal) {
  546. this.setData({
  547. showModal: false
  548. });
  549. } else {
  550. this.setData({
  551. showAddModal: false
  552. });
  553. }
  554. },
  555. // 行点击事件:显示编辑和删除弹窗
  556. onRowClick: function(e) {
  557. const index = e.currentTarget.dataset.index;
  558. const row = e.currentTarget.dataset.row;
  559. this.setData({
  560. currentRow: { index: index, row: row },
  561. showModal: true // 显示编辑删除弹窗
  562. });
  563. }
  564. });