Visualizatio.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. // 下载模板函数
  81. onDownloadTemplate: function() {
  82. wx.showLoading({
  83. title: '下载中...',
  84. });
  85. const tableName = 'current_reduce'; // 或者根据需要选择表名
  86. const format = 'excel'; // 或者 'csv' 作为模板格式
  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. wx.showToast({
  108. title: '文件已保存',
  109. icon: 'success'
  110. });
  111. // 触发文件下载
  112. wx.openDocument({
  113. filePath: filePath,
  114. fileType: format === 'excel' ? 'xlsx' : 'csv',
  115. success: () => {
  116. console.log('文件打开成功');
  117. },
  118. fail: (error) => {
  119. console.error('文件打开失败', error);
  120. wx.showToast({
  121. title: '打开文件失败',
  122. icon: 'none'
  123. });
  124. }
  125. });
  126. },
  127. fail: (err) => {
  128. wx.showToast({
  129. title: '文件保存失败',
  130. icon: 'none'
  131. });
  132. console.error('文件保存失败', err);
  133. }
  134. });
  135. } else {
  136. wx.showToast({
  137. title: '下载失败',
  138. icon: 'none'
  139. });
  140. }
  141. },
  142. fail: (err) => {
  143. wx.hideLoading();
  144. wx.showToast({
  145. title: '请求失败,请重试',
  146. icon: 'none'
  147. });
  148. console.error('请求失败:', err);
  149. }
  150. });
  151. },
  152. // 导出数据按钮点击事件
  153. onExport: function () {
  154. const tableName = this.data.tableName;
  155. const fileFormat = this.data.fileFormat;
  156. wx.showLoading({
  157. title: '导出中...',
  158. });
  159. // 向后端发送请求,获取表格数据并导出
  160. wx.request({
  161. url: `https://soilgd.com:5000/export_data?table=${tableName}&format=${fileFormat}`,
  162. method: 'GET',
  163. responseType: 'arraybuffer', // 处理二进制文件
  164. success: (res) => {
  165. wx.hideLoading();
  166. // 确保响应体返回的数据是有效的文件
  167. if (res.statusCode === 200) {
  168. const fileName = `${tableName}_data.${fileFormat === 'excel' ? 'xlsx' : 'csv'}`;
  169. const filePath = wx.env.USER_DATA_PATH + '/' + fileName;
  170. // 保存文件到本地
  171. wx.getFileSystemManager().writeFile({
  172. filePath: filePath,
  173. data: res.data,
  174. encoding: 'binary',
  175. success: () => {
  176. wx.showToast({
  177. title: '文件已保存',
  178. icon: 'success'
  179. });
  180. // 打开已保存的文件
  181. wx.openDocument({
  182. filePath: filePath,
  183. fileType: fileFormat === 'excel' ? 'xlsx' : 'csv',
  184. success: () => {
  185. console.log('文件打开成功');
  186. },
  187. fail: (error) => {
  188. console.error('文件打开失败', error);
  189. wx.showToast({
  190. title: '打开文件失败',
  191. icon: 'none'
  192. });
  193. }
  194. });
  195. },
  196. fail: (err) => {
  197. wx.showToast({
  198. title: '文件保存失败',
  199. icon: 'none'
  200. });
  201. console.error('文件保存失败', err);
  202. }
  203. });
  204. } else {
  205. wx.showToast({
  206. title: '导出失败,请重试',
  207. icon: 'none'
  208. });
  209. }
  210. },
  211. fail: (err) => {
  212. wx.hideLoading();
  213. wx.showToast({
  214. title: '请求失败,请重试',
  215. icon: 'none'
  216. });
  217. console.error('请求失败:', err);
  218. }
  219. });
  220. },
  221. // 导入数据功能
  222. onImport: function () {
  223. wx.chooseMessageFile({
  224. count: 1,
  225. type: 'file',
  226. extension: ['xlsx', 'csv'], // 允许上传的文件类型
  227. success: (res) => {
  228. const filePath = res.tempFiles[0].path;
  229. const fileName = res.tempFiles[0].name;
  230. wx.showLoading({ title: '上传中...' });
  231. // 上传文件到后端
  232. wx.uploadFile({
  233. url: 'https://soilgd.com:5000/import_data', // 后端接口
  234. filePath: filePath,
  235. name: 'file',
  236. formData: {
  237. table: this.data.tableName, // 表名
  238. fileName: fileName
  239. },
  240. success: (res) => {
  241. wx.hideLoading();
  242. const responseData = JSON.parse(res.data);
  243. if (responseData.success) {
  244. // 获取后端返回的结果
  245. const { total_data, new_data, duplicate_data, duplicate_details } = responseData;
  246. // 显示导入结果
  247. wx.showModal({
  248. title: '导入结果',
  249. content: `总数据: ${total_data} 条\n新增: ${new_data} 条\n重复: ${duplicate_data} 条`,
  250. success: () => {
  251. // 如果有重复数据,跳转到重复数据详情页面
  252. if (duplicate_data > 0) {
  253. wx.navigateTo({
  254. url: '/pages/duplicateDetails/duplicateDetails', // 重复数据详情页面
  255. success: (page) => {
  256. // 将重复数据传递给详情页面
  257. page.setData({ duplicateDetails: duplicate_details });
  258. }
  259. });
  260. }
  261. }
  262. });
  263. // 重新加载数据
  264. this.LoadData();
  265. } else {
  266. wx.showToast({
  267. title: responseData.message || '导入失败,请检查文件格式',
  268. icon: 'none'
  269. });
  270. }
  271. },
  272. fail: (err) => {
  273. wx.hideLoading();
  274. wx.showToast({
  275. title: '导入失败,请重试',
  276. icon: 'none'
  277. });
  278. console.error('文件上传失败:', err);
  279. }
  280. });
  281. },
  282. fail: (err) => {
  283. console.error('文件选择失败:', err);
  284. }
  285. });
  286. },
  287. // 新增按钮点击,显示新增弹窗
  288. onAdd: function() {
  289. console.log("新增按钮被点击了"); // 调试日志
  290. this.setData({
  291. showAddModal: true,
  292. newData: { // 重置新增数据
  293. Q_over_b: "",
  294. pH: "",
  295. OM: "",
  296. CL: "",
  297. H: "",
  298. Al: ""
  299. }
  300. });
  301. console.log("showAddModal: ", this.data.showAddModal); // 确认数据更新
  302. },
  303. // 输入框绑定:更新新增数据的对应字段
  304. onInputQ_over_b: function(e) {
  305. const value = e.detail.value;
  306. const filteredValue = value.replace(/[^0-9.]/g, '');
  307. this.setData({
  308. 'newData.Q_over_b': filteredValue
  309. });
  310. },
  311. onInputpH: function(e) {
  312. const value = e.detail.value;
  313. const filteredValue = value.replace(/[^0-9.]/g, '');
  314. this.setData({
  315. 'newData.pH': filteredValue
  316. });
  317. },
  318. onInputOM: function(e) {
  319. const value = e.detail.value;
  320. const filteredValue = value.replace(/[^0-9.]/g, '');
  321. this.setData({
  322. 'newData.OM': filteredValue
  323. });
  324. },
  325. onInputCL: function(e) {
  326. const value = e.detail.value;
  327. const filteredValue = value.replace(/[^0-9.]/g, '');
  328. this.setData({
  329. 'newData.CL': filteredValue
  330. });
  331. },
  332. onInputH: function(e) {
  333. const value = e.detail.value;
  334. const filteredValue = value.replace(/[^0-9.]/g, '');
  335. this.setData({
  336. 'newData.H': filteredValue
  337. });
  338. },
  339. onInputAl: function(e) {
  340. const value = e.detail.value;
  341. const filteredValue = value.replace(/[^0-9.]/g, '');
  342. this.setData({
  343. 'newData.Al': filteredValue
  344. });
  345. },
  346. // 提交新增数据
  347. onSubmitAdd: function() {
  348. const newRow = this.data.newData;
  349. if (Object.values(newRow).some(value => !value)) {
  350. wx.showToast({
  351. title: '所有字段都必须填写!',
  352. icon: 'none'
  353. });
  354. return;
  355. }
  356. wx.request({
  357. url: 'https://soilgd.com:5000/add_item',
  358. method: 'POST',
  359. header: {
  360. 'Content-Type': 'application/json'
  361. },
  362. data: {
  363. table: 'current_reduce',
  364. item: newRow
  365. },
  366. success: (res) => {
  367. if (res.data.success) {
  368. this.setData({
  369. rows: [...this.data.rows, newRow],
  370. showAddModal: false
  371. });
  372. wx.showToast({
  373. title: '新增成功',
  374. icon: 'success'
  375. });
  376. this.LoadData();
  377. } else if (res.statusCode === 409) {
  378. wx.showToast({
  379. title: '重复数据,已有相同的数据项存在。',
  380. icon: 'none'
  381. });
  382. } else {
  383. wx.showToast({
  384. title: '新增失败',
  385. icon: 'none'
  386. });
  387. }
  388. },
  389. fail: (err) => {
  390. wx.showToast({
  391. title: '请求失败,请重试',
  392. icon: 'none'
  393. });
  394. console.error('请求失败:', err);
  395. }
  396. });
  397. },
  398. // 取消新增数据
  399. onCancel: function() {
  400. this.setData({
  401. showAddModal: false
  402. });
  403. },
  404. // 编辑按钮点击
  405. onEdit: function(e) {
  406. const { index, row } = this.data.currentRow;
  407. console.log(row);
  408. // 检查 currentRow 是否有定义并且包含数据
  409. if (row) {
  410. this.setData({
  411. isEditing: true,
  412. showModal: false,
  413. showAddModal: true, // 显示编辑弹窗
  414. newData: row, // 将当前行的数据复制到 newData 中,以便在表单中显示
  415. currentRow: { index: index, row: row } // 保存当前行的信息,以便在提交时使用
  416. });
  417. } else {
  418. wx.showToast({
  419. title: '数据加载失败,请重试',
  420. icon: 'none'
  421. });
  422. }
  423. },
  424. // 提交编辑数据
  425. onSubmitEdit: function() {
  426. const updatedRow = this.data.newData;
  427. const { index } = this.data.currentRow;
  428. if (Object.values(updatedRow).some(value => !value)) {
  429. wx.showToast({
  430. title: '所有字段都必须填写!',
  431. icon: 'none'
  432. });
  433. return;
  434. }
  435. wx.request({
  436. url: 'https://soilgd.com:5000/update_item',
  437. method: 'PUT',
  438. header: {
  439. 'Content-Type': 'application/json'
  440. },
  441. data: {
  442. table: 'current_reduce',
  443. item: updatedRow
  444. },
  445. success: (res) => {
  446. if (res.data.success) {
  447. // 更新成功后,更新前端数据
  448. let rows = this.data.rows;
  449. rows[index] = updatedRow; // 用更新后的数据替换旧数据
  450. this.setData({
  451. rows: rows,
  452. showAddModal: false // 关闭编辑弹窗
  453. });
  454. wx.showToast({
  455. title: '编辑成功',
  456. icon: 'success'
  457. });
  458. this.LoadData();
  459. } else {
  460. wx.showToast({
  461. title: '编辑失败',
  462. icon: 'none'
  463. });
  464. }
  465. },
  466. fail: (err) => {
  467. wx.showToast({
  468. title: '请求失败,请重试',
  469. icon: 'none'
  470. });
  471. console.error('请求失败:', err);
  472. }
  473. });
  474. },
  475. // 删除按钮点击
  476. onDelete: function() {
  477. const { index, row } = this.data.currentRow;
  478. console.log("当前选中行的数据:", this.data.currentRow);
  479. const condition = `id=${row.id}`; // 使用条件进行删除
  480. // 发送 DELETE 请求
  481. wx.request({
  482. url: 'https://soilgd.com:5000/delete_item', // 后端接口地址
  483. method: 'POST', // 使用 POST 请求
  484. data: {
  485. table: 'current_reduce', // 目标表
  486. condition: condition // 删除条件
  487. },
  488. success: (res) => {
  489. if (res.data.success) {
  490. // 删除成功后,更新前端数据
  491. let rows = this.data.rows;
  492. rows.splice(index, 1); // 从数据中删除选中的行
  493. this.setData({
  494. rows: rows,
  495. showModal: false // 隐藏编辑删除弹窗
  496. });
  497. wx.showToast({
  498. title: '删除成功',
  499. icon: 'success'
  500. });
  501. // 重新获取数据
  502. this.LoadData(); // 重新加载数据
  503. } else {
  504. wx.showToast({
  505. title: '删除失败',
  506. icon: 'none'
  507. });
  508. }
  509. },
  510. fail: (err) => {
  511. wx.showToast({
  512. title: '请求失败,请重试',
  513. icon: 'none'
  514. });
  515. console.error('请求失败:', err);
  516. }
  517. });
  518. },
  519. onSubmit: function() {
  520. if (this.data.isEditing) {
  521. this.onSubmitEdit();
  522. } else {
  523. this.onSubmitAdd();
  524. }
  525. },
  526. // 取消编辑删除弹窗
  527. onCancel: function() {
  528. if (this.data.showModal) {
  529. this.setData({
  530. showModal: false
  531. });
  532. } else {
  533. this.setData({
  534. showAddModal: false
  535. });
  536. }
  537. },
  538. // 行点击事件:显示编辑和删除弹窗
  539. onRowClick: function(e) {
  540. const index = e.currentTarget.dataset.index;
  541. const row = e.currentTarget.dataset.row;
  542. this.setData({
  543. currentRow: { index: index, row: row },
  544. showModal: true // 显示编辑删除弹窗
  545. });
  546. }
  547. });