Visualizatio.js 18 KB

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