DataSync.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. // 注册 Vant 组件
  2. Vue.use(vant.NavBar);
  3. Vue.use(vant.Icon);
  4. Vue.use(vant.Tag);
  5. Vue.use(vant.Loading);
  6. Vue.use(vant.Notify);
  7. Vue.use(vant.Dialog);
  8. Vue.use(vant.Toast);
  9. Vue.use(vant.Collapse);
  10. Vue.use(vant.CollapseItem);
  11. Vue.use(vant.Field);
  12. Vue.use(vant.Form);
  13. Vue.use(vant.Button);
  14. Vue.use(vant.Overlay);
  15. var app = new Vue({
  16. el: "#app",
  17. data: {
  18. // 同步状态
  19. isSyncing: false,
  20. syncButtonText: '开始同步',
  21. // 进度相关
  22. showProgress: false,
  23. progressPercent: 0,
  24. progressText: '准备同步',
  25. // 统计数据
  26. showStats: false,
  27. totalTasks: 0,
  28. successCount: 0,
  29. errorCount: 0,
  30. runningCount: 0,
  31. // 上传任务列表
  32. uploadTasks: [
  33. { id: 1, taskName: '盘点数据上传', status: 'pending' },
  34. // { id: 2, taskName: '资产数据上传', status: 'pending' },
  35. ],
  36. // 下载任务列表
  37. downloadTasks: [
  38. { id: 1, taskName: '盘点数据下载', status: 'pending' },
  39. // { id: 2, taskName: '资产数据下载', status: 'pending' },
  40. ],
  41. // 折叠面板激活的名称
  42. activeNames: ['upload', 'download'],
  43. // IndexDB 数据库实例
  44. checkVouchDb: null,
  45. // 登录相关
  46. loginShow: false,
  47. username: null,
  48. password: null,
  49. clientId: null,
  50. // 表单验证
  51. usernameError: false,
  52. usernameErrorMsg: '',
  53. passwordError: false,
  54. passwordErrorMsg: '',
  55. },
  56. methods: {
  57. /**
  58. * 返回上一页
  59. */
  60. goBack: function () {
  61. window.location.href = './Menu.html';
  62. },
  63. /**
  64. * 开始同步
  65. */
  66. startSync: function () {
  67. var _self = this;
  68. // 显示确认对话框
  69. vant.Dialog.confirm({
  70. title: '确认同步',
  71. message: '确定要开始同步数据吗?',
  72. }).then(function () {
  73. // 确认后先判断登录状态
  74. _self.judgementLogin();
  75. }).catch(function () {
  76. // 用户取消
  77. });
  78. },
  79. /**
  80. * 判断是否登录
  81. * 1.判断网络是否连接
  82. * 2.判断token是否为null
  83. * 3.判断token是否正确
  84. */
  85. judgementLogin: function () {
  86. var _self = this;
  87. $.ajax({
  88. url: Common.getApi('/authApi/LoginResource/getCurrentDate'),
  89. type: 'get',
  90. dataType: "text",
  91. success: function (data) {
  92. var token = localStorage.getItem("token");
  93. if (token != null) {
  94. $.ajax({
  95. url: Common.getApi('/api/userResource/authenticationToken'),
  96. type: 'get',
  97. data: {
  98. token: token
  99. },
  100. success: function (data) {
  101. if (data.errorCode != 0) {
  102. _self.loginShow = true;
  103. } else {
  104. // token有效,直接执行同步
  105. _self.executeSync();
  106. }
  107. },
  108. error: function (e) { },
  109. });
  110. } else {
  111. _self.loginShow = true;
  112. }
  113. },
  114. error: function (e) {
  115. if (e.readyState == 0) {
  116. vant.Dialog.alert({
  117. title: '错误',
  118. message: '网络未连接无法进行同步',
  119. theme: 'round-button',
  120. });
  121. }
  122. },
  123. });
  124. },
  125. /**
  126. * 登录
  127. */
  128. login: function () {
  129. var _self = this;
  130. var username = _self.username;
  131. var password = _self.password;
  132. var loginData = {
  133. userName: username,
  134. password: password,
  135. accountDateTime: '',
  136. languageId: 'zh-CN'
  137. };
  138. $.ajax({
  139. url: Common.getApi('/authApi/LoginResource/login'),
  140. type: 'post',
  141. data: loginData,
  142. contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
  143. success: function (loginInfo) {
  144. var json_LoginInfo = JSON.stringify(loginInfo);
  145. localStorage.setItem('json_LoginInfo', json_LoginInfo);
  146. localStorage.setItem('token', loginInfo.data.token);
  147. localStorage.setItem('account', loginInfo.data.accountId);
  148. localStorage.setItem('clientId', loginInfo.data.loginClientId);
  149. $.ajax({
  150. type: "post",
  151. url: Common.getApi('/api/TokenClientResource/saveTokenClient'),
  152. contentType: "application/json",
  153. beforeSend: function (request) {
  154. Common.addTokenToRequest(request);
  155. },
  156. success: function (data) {
  157. _self.loginShow = false;
  158. vant.Notify({
  159. type: 'success',
  160. message: '登录成功',
  161. duration: 1000,
  162. });
  163. _self.clientId = loginInfo.data.loginClientId;
  164. // 登录成功后执行同步
  165. _self.executeSync();
  166. },
  167. error: function (e) {
  168. Common.processExceptionVant(e);
  169. }
  170. });
  171. },
  172. error: function (e) {
  173. vant.Notify({
  174. type: 'danger',
  175. message: '用户名或密码错误',
  176. duration: 1000,
  177. });
  178. },
  179. });
  180. },
  181. /**
  182. * 取消登录
  183. */
  184. onCancelLogin: function () {
  185. var _self = this;
  186. _self.loginShow = false;
  187. _self.username = null;
  188. _self.password = null;
  189. _self.resetFormErrors();
  190. },
  191. /**
  192. * 验证用户名
  193. */
  194. validateUsername: function () {
  195. var _self = this;
  196. if (!_self.username || _self.username.trim() === '') {
  197. _self.usernameError = true;
  198. _self.usernameErrorMsg = '请输入用户名';
  199. return false;
  200. } else {
  201. _self.usernameError = false;
  202. _self.usernameErrorMsg = '';
  203. return true;
  204. }
  205. },
  206. /**
  207. * 验证密码
  208. */
  209. validatePassword: function () {
  210. var _self = this;
  211. if (!_self.password || _self.password.trim() === '') {
  212. _self.passwordError = true;
  213. _self.passwordErrorMsg = '请输入密码';
  214. return false;
  215. } else {
  216. _self.passwordError = false;
  217. _self.passwordErrorMsg = '';
  218. return true;
  219. }
  220. },
  221. /**
  222. * 重置表单错误状态
  223. */
  224. resetFormErrors: function () {
  225. var _self = this;
  226. _self.usernameError = false;
  227. _self.usernameErrorMsg = '';
  228. _self.passwordError = false;
  229. _self.passwordErrorMsg = '';
  230. },
  231. /**
  232. * 处理登录表单提交
  233. */
  234. handleLogin: function () {
  235. var _self = this;
  236. // 验证表单
  237. var usernameValid = _self.validateUsername();
  238. var passwordValid = _self.validatePassword();
  239. if (usernameValid && passwordValid) {
  240. // 表单验证通过,执行登录
  241. _self.login();
  242. }
  243. },
  244. /**
  245. * 执行同步流程
  246. */
  247. executeSync: function () {
  248. var _self = this;
  249. // 重置状态
  250. _self.resetState();
  251. // 开始同步
  252. _self.isSyncing = true;
  253. _self.syncButtonText = '同步中...';
  254. _self.showProgress = true;
  255. _self.showStats = true;
  256. // 计算总任务数
  257. _self.totalTasks = _self.uploadTasks.length + _self.downloadTasks.length;
  258. vant.Toast.loading({
  259. message: '同步开始...',
  260. forbidClick: true,
  261. duration: 1500,
  262. });
  263. // 延迟开始,显示加载提示
  264. setTimeout(function () {
  265. _self.startUploadTasks();
  266. }, 1000);
  267. },
  268. /**
  269. * 重置状态
  270. */
  271. resetState: function () {
  272. var _self = this;
  273. // 重置进度
  274. _self.progressPercent = 0;
  275. _self.progressText = '准备同步';
  276. // 重置统计
  277. _self.successCount = 0;
  278. _self.errorCount = 0;
  279. _self.runningCount = 0;
  280. // 重置上传任务状态
  281. _self.uploadTasks.forEach(function (task) {
  282. task.status = 'pending';
  283. });
  284. // 重置下载任务状态
  285. _self.downloadTasks.forEach(function (task) {
  286. task.status = 'pending';
  287. });
  288. },
  289. /**
  290. * 开始上传任务
  291. */
  292. startUploadTasks: function () {
  293. var _self = this;
  294. _self.progressText = '开始上传数据';
  295. // 顺序执行上传任务
  296. _self.executeTasksSequentially(_self.uploadTasks, '上传', function () {
  297. // 上传完成后,开始下载
  298. _self.startDownloadTasks();
  299. });
  300. },
  301. /**
  302. * 开始下载任务
  303. */
  304. startDownloadTasks: function () {
  305. var _self = this;
  306. _self.progressText = '开始下载数据';
  307. // 顺序执行下载任务
  308. _self.executeTasksSequentially(_self.downloadTasks, '下载', function () {
  309. // 全部完成
  310. _self.onSyncComplete();
  311. });
  312. },
  313. /**
  314. * 顺序执行任务列表
  315. * @param {Array} tasks - 任务列表
  316. * @param {String} type - 任务类型(上传/下载)
  317. * @param {Function} callback - 完成回调
  318. */
  319. executeTasksSequentially: function (tasks, type, callback) {
  320. var _self = this;
  321. var currentIndex = 0;
  322. function executeNext() {
  323. if (currentIndex >= tasks.length) {
  324. // 所有任务完成
  325. callback();
  326. return;
  327. }
  328. var task = tasks[currentIndex];
  329. _self.executeTask(task, type, function () {
  330. currentIndex++;
  331. executeNext();
  332. });
  333. }
  334. executeNext();
  335. },
  336. /**
  337. * 执行单个任务
  338. * @param {Object} task - 任务对象
  339. * @param {String} type - 任务类型
  340. * @param {Function} callback - 完成回调
  341. */
  342. executeTask: function (task, type, callback) {
  343. var _self = this;
  344. // 更新状态为运行中
  345. task.status = 'running';
  346. _self.runningCount++;
  347. _self.progressText = type + '中: ' + task.taskName;
  348. // 根据任务名称选择对应的 API 调用
  349. var apiPromise;
  350. if (task.taskName === '盘点数据上传') {
  351. apiPromise = _self.uploadInventoryData();
  352. } else if (task.taskName === '盘点数据下载') {
  353. apiPromise = _self.downloadInventoryData();
  354. } else {
  355. // 未知任务类型,直接失败
  356. apiPromise = Promise.reject('未知的任务类型');
  357. }
  358. // 执行API调用
  359. apiPromise.then(function (result) {
  360. // 成功
  361. task.status = 'success';
  362. _self.successCount++;
  363. _self.runningCount--;
  364. // 更新进度
  365. _self.updateProgress();
  366. var message = task.taskName + ' 成功';
  367. // if (result.count !== undefined) {
  368. // message += ' (' + result.count + '条)';
  369. // }
  370. vant.Notify({
  371. type: 'success',
  372. message: message,
  373. duration: 1000,
  374. });
  375. // 延迟继续下一个任务
  376. setTimeout(callback, 500);
  377. }).catch(function (error) {
  378. // 失败
  379. task.status = 'error';
  380. _self.errorCount++;
  381. _self.runningCount--;
  382. // 更新进度
  383. _self.updateProgress();
  384. vant.Notify({
  385. type: 'danger',
  386. message: task.taskName + ' 失败: ' + error,
  387. duration: 1500,
  388. });
  389. // 延迟继续下一个任务(即使失败也继续)
  390. setTimeout(callback, 500);
  391. });
  392. },
  393. /**
  394. * 清除所有 IndexDB 数据
  395. * @returns {Promise}
  396. */
  397. clearAllIndexDBData: function () {
  398. var _self = this;
  399. return new Promise(function (resolve, reject) {
  400. // 清除 uploadQueue 的所有数据
  401. _self.checkVouchDb.getAll('uploadQueue', function (uploadQueueData) {
  402. var deleteUploadPromises = [];
  403. if (uploadQueueData && uploadQueueData.length > 0) {
  404. uploadQueueData.forEach(function (item) {
  405. deleteUploadPromises.push(new Promise(function (res, rej) {
  406. _self.checkVouchDb.deleteOne('uploadQueue', item.checkVouchId, function () {
  407. res();
  408. }, function (error) {
  409. rej(error);
  410. });
  411. }));
  412. });
  413. }
  414. Promise.all(deleteUploadPromises).then(function () {
  415. console.log('uploadQueue 数据已清除');
  416. // 清除 checkVouchList 的所有数据
  417. _self.checkVouchDb.getAll('checkVouchList', function (checkVouchListData) {
  418. var deleteCheckPromises = [];
  419. if (checkVouchListData && checkVouchListData.length > 0) {
  420. checkVouchListData.forEach(function (item) {
  421. deleteCheckPromises.push(new Promise(function (res, rej) {
  422. _self.checkVouchDb.deleteOne('checkVouchList', item.checkVouchId, function () {
  423. res();
  424. }, function (error) {
  425. rej(error);
  426. });
  427. }));
  428. });
  429. }
  430. Promise.all(deleteCheckPromises).then(function () {
  431. console.log('checkVouchList 数据已清除');
  432. resolve();
  433. }).catch(function (error) {
  434. reject('清除 checkVouchList 失败: ' + error);
  435. });
  436. }, function (error) {
  437. reject('获取 checkVouchList 失败: ' + error);
  438. });
  439. }).catch(function (error) {
  440. reject('清除 uploadQueue 失败: ' + error);
  441. });
  442. }, function (error) {
  443. // 如果获取失败,尝试继续清除 checkVouchList
  444. console.warn('获取 uploadQueue 失败,跳过:', error);
  445. _self.checkVouchDb.getAll('checkVouchList', function (checkVouchListData) {
  446. var deleteCheckPromises = [];
  447. if (checkVouchListData && checkVouchListData.length > 0) {
  448. checkVouchListData.forEach(function (item) {
  449. deleteCheckPromises.push(new Promise(function (res, rej) {
  450. _self.checkVouchDb.deleteOne('checkVouchList', item.checkVouchId, function () {
  451. res();
  452. }, function (error) {
  453. rej(error);
  454. });
  455. }));
  456. });
  457. }
  458. Promise.all(deleteCheckPromises).then(function () {
  459. console.log('checkVouchList 数据已清除');
  460. resolve();
  461. }).catch(function (error) {
  462. reject('清除 checkVouchList 失败: ' + error);
  463. });
  464. }, function (error) {
  465. reject('获取 checkVouchList 失败: ' + error);
  466. });
  467. });
  468. });
  469. },
  470. /**
  471. * 执行API调用 - 下载盘点数据
  472. * @returns {Promise}
  473. */
  474. downloadInventoryData: function () {
  475. var _self = this;
  476. return new Promise(function (resolve, reject) {
  477. // 下载前先清空所有 IndexDB 数据
  478. console.log('下载前清空所有 IndexDB 数据');
  479. _self.clearAllIndexDBData().then(function () {
  480. console.log('IndexDB 已清空,开始下载数据');
  481. // 执行下载
  482. $.ajax({
  483. url: Common.getApi('/api/CheckVouchResource/inventoryDataDownload'),
  484. type: 'post',
  485. contentType: "application/json",
  486. beforeSend: function (request) {
  487. Common.addTokenToRequest(request);
  488. },
  489. success: function (response) {
  490. if (response.errorCode === 0 && response.datas) {
  491. // 存储盘点单数据到 IndexDB(完整保存,包含 checkVouchDate 信息)
  492. var savePromises = [];
  493. response.datas.forEach(function (checkVouch) {
  494. savePromises.push(new Promise(function (res, rej) {
  495. // 直接保存完整的盘点单数据到 checkVouchList
  496. // 在 AssetInventoryCheck.js 加载时,会根据 checkVouchDate 区分已盘和待盘
  497. _self.checkVouchDb.put('checkVouchList', checkVouch, function () {
  498. var totalItems = checkVouch.cfCheckVouchsResponses ? checkVouch.cfCheckVouchsResponses.length : 0;
  499. console.log('盘点单保存成功:', checkVouch.checkVouchId, ',共', totalItems, '条数据');
  500. res();
  501. }, function (error) {
  502. console.error('盘点单保存失败:', error);
  503. rej(error);
  504. });
  505. }));
  506. });
  507. // 等待所有盘点单保存完成
  508. Promise.all(savePromises).then(function () {
  509. resolve({
  510. errorCode: 0,
  511. message: '盘点数据下载成功',
  512. count: response.datas.length
  513. });
  514. }).catch(function (error) {
  515. reject('保存盘点数据失败: ' + error);
  516. });
  517. } else {
  518. reject(response.errorMessage || '下载盘点数据失败');
  519. }
  520. },
  521. error: function (xhr, status, error) {
  522. console.error('下载盘点数据失败:', error);
  523. reject('网络错误: ' + error);
  524. }
  525. });
  526. }).catch(function (error) {
  527. // 清空 IndexDB 失败
  528. console.error('清空 IndexDB 失败:', error);
  529. reject('清空 IndexDB 失败: ' + error);
  530. });
  531. });
  532. },
  533. /**
  534. * 执行API调用 - 上传盘点数据
  535. * @returns {Promise}
  536. */
  537. uploadInventoryData: function () {
  538. var _self = this;
  539. return new Promise(function (resolve, reject) {
  540. // 从 IndexDB 读取待上传的盘点数据
  541. _self.checkVouchDb.getAll('uploadQueue', function (uploadDataList) {
  542. // 如果没有数据,使用空数组
  543. var dataToUpload = uploadDataList || [];
  544. var hasData = dataToUpload.length > 0;
  545. console.log('准备上传盘点数据,数据量:', dataToUpload.length);
  546. // 上传数据 - 数据结构为数组,无论有没有数据都要上传
  547. $.ajax({
  548. url: Common.getApi('/api/CheckVouchResource/inventoryDataUpload'),
  549. type: 'POST',
  550. contentType: 'application/json',
  551. data: JSON.stringify(dataToUpload),
  552. beforeSend: function (request) {
  553. Common.addTokenToRequest(request);
  554. },
  555. success: function (response) {
  556. if (response.errorCode === 0) {
  557. // 上传成功后,清除所有 IndexDB 数据
  558. console.log('上传成功,开始清除所有 IndexDB 数据');
  559. // 统计总的盘点条数
  560. var totalCount = 0;
  561. if (hasData) {
  562. dataToUpload.forEach(function (item) {
  563. if (item.cfCheckVouchsRequests) {
  564. totalCount += item.cfCheckVouchsRequests.length;
  565. }
  566. });
  567. }
  568. // 清除所有数据
  569. _self.clearAllIndexDBData().then(function () {
  570. console.log('所有 IndexDB 数据已清除,准备重新下载');
  571. // 清除成功后,自动触发下载
  572. return _self.downloadInventoryData();
  573. }).then(function (downloadResult) {
  574. console.log('重新下载完成:', downloadResult);
  575. resolve({
  576. errorCode: 0,
  577. message: '盘点数据上传成功,已重新下载最新数据',
  578. count: totalCount
  579. });
  580. }).catch(function (error) {
  581. console.error('清除或重新下载失败:', error);
  582. // 即使清除或下载失败,上传已成功
  583. resolve({
  584. errorCode: 0,
  585. message: '盘点数据上传成功(但重新下载失败: ' + error + ')',
  586. count: totalCount
  587. });
  588. });
  589. } else {
  590. reject(response.errorMessage || '上传盘点数据失败');
  591. }
  592. },
  593. error: function (xhr, status, error) {
  594. console.error('上传盘点数据失败:', error);
  595. reject('网络错误: ' + error);
  596. }
  597. });
  598. }, function (error) {
  599. // 如果读取失败,也尝试上传空数组
  600. console.error('读取待上传数据失败,将上传空数组:', error);
  601. $.ajax({
  602. url: Common.getApi('/api/CheckVouchResource/inventoryDataUpload'),
  603. type: 'POST',
  604. contentType: 'application/json',
  605. data: JSON.stringify([]),
  606. beforeSend: function (request) {
  607. Common.addTokenToRequest(request);
  608. },
  609. success: function (response) {
  610. if (response.errorCode === 0) {
  611. resolve({
  612. errorCode: 0,
  613. message: '没有需要上传的盘点数据',
  614. count: 0
  615. });
  616. } else {
  617. reject(response.errorMessage || '上传盘点数据失败');
  618. }
  619. },
  620. error: function (xhr, status, error) {
  621. console.error('上传盘点数据失败:', error);
  622. reject('网络错误: ' + error);
  623. }
  624. });
  625. });
  626. });
  627. },
  628. /**
  629. * 更新进度
  630. */
  631. updateProgress: function () {
  632. var _self = this;
  633. // 使用calculateStats来自动计算所有统计数据
  634. _self.calculateStats();
  635. },
  636. /**
  637. * 同步完成
  638. */
  639. onSyncComplete: function () {
  640. var _self = this;
  641. _self.isSyncing = false;
  642. _self.progressPercent = 100;
  643. _self.progressText = '同步完成';
  644. _self.syncButtonText = '同步完成';
  645. // 显示完成消息
  646. var message = '同步完成!成功: ' + _self.successCount + ' 个,失败: ' + _self.errorCount + ' 个';
  647. if (_self.errorCount === 0) {
  648. vant.Dialog.alert({
  649. title: '同步成功',
  650. message: '所有数据已成功同步!',
  651. theme: 'round-button',
  652. }).then(function () {
  653. _self.resetButtonText();
  654. });
  655. } else {
  656. vant.Dialog.alert({
  657. title: '同步完成',
  658. message: message,
  659. theme: 'round-button',
  660. }).then(function () {
  661. _self.resetButtonText();
  662. });
  663. }
  664. },
  665. /**
  666. * 重置按钮文本
  667. */
  668. resetButtonText: function () {
  669. var _self = this;
  670. setTimeout(function () {
  671. _self.syncButtonText = '开始同步';
  672. }, 1000);
  673. },
  674. /**
  675. * 添加上传任务(支持动态添加)
  676. * @param {String} taskName - 任务名称
  677. */
  678. addUploadTask: function (taskName) {
  679. var _self = this;
  680. var newId = _self.uploadTasks.length > 0
  681. ? Math.max.apply(Math, _self.uploadTasks.map(function (t) { return t.id; })) + 1
  682. : 1;
  683. _self.uploadTasks.push({
  684. id: newId,
  685. taskName: taskName,
  686. status: 'pending'
  687. });
  688. },
  689. /**
  690. * 添加下载任务(支持动态添加)
  691. * @param {String} taskName - 任务名称
  692. */
  693. addDownloadTask: function (taskName) {
  694. var _self = this;
  695. var newId = _self.downloadTasks.length > 0
  696. ? Math.max.apply(Math, _self.downloadTasks.map(function (t) { return t.id; })) + 1
  697. : 1;
  698. _self.downloadTasks.push({
  699. id: newId,
  700. taskName: taskName,
  701. status: 'pending'
  702. });
  703. },
  704. /**
  705. * 清空所有任务
  706. */
  707. clearAllTasks: function () {
  708. var _self = this;
  709. _self.uploadTasks = [];
  710. _self.downloadTasks = [];
  711. _self.resetState();
  712. },
  713. /**
  714. * 计算统计数据
  715. */
  716. calculateStats: function () {
  717. var _self = this;
  718. var allTasks = _self.uploadTasks.concat(_self.downloadTasks);
  719. _self.totalTasks = allTasks.length;
  720. _self.successCount = allTasks.filter(function (t) { return t.status === 'success'; }).length;
  721. _self.errorCount = allTasks.filter(function (t) { return t.status === 'error'; }).length;
  722. _self.runningCount = allTasks.filter(function (t) { return t.status === 'running'; }).length;
  723. // 只有在同步开始后才显示统计卡片
  724. // 初始状态(所有任务都是pending)时不显示
  725. if (_self.successCount > 0 || _self.errorCount > 0 || _self.runningCount > 0) {
  726. _self.showStats = true;
  727. _self.showProgress = true;
  728. _self.progressPercent = Math.round(((_self.successCount + _self.errorCount) / _self.totalTasks) * 100);
  729. if (_self.progressPercent === 100) {
  730. _self.progressText = '同步完成';
  731. }
  732. }
  733. },
  734. /**
  735. * 验证整个表单
  736. */
  737. validateForm: function () {
  738. var _self = this;
  739. var usernameValid = _self.validateUsername();
  740. var passwordValid = _self.validatePassword();
  741. return usernameValid && passwordValid;
  742. },
  743. /**
  744. * 初始化页面数据
  745. */
  746. initData: function () {
  747. var _self = this;
  748. console.log('初始化数据同步页面');
  749. // 初始化 IndexDB 数据库
  750. var objectStoreDefines = [
  751. {
  752. name: 'checkVouchList',
  753. defineOption: { keyPath: 'checkVouchId' },
  754. indexDefineList: null
  755. },
  756. {
  757. name: 'uploadQueue',
  758. defineOption: { keyPath: 'checkVouchId' },
  759. indexDefineList: null
  760. }
  761. ];
  762. _self.checkVouchDb = new IndexDbFactory('checkVouchDB', objectStoreDefines, 1);
  763. _self.checkVouchDb.open(function () {
  764. console.log('盘点数据库初始化成功');
  765. }, function () {
  766. console.error('盘点数据库初始化失败');
  767. vant.Dialog.alert({
  768. title: '错误',
  769. message: '数据库初始化失败,数据同步功能不可用。',
  770. theme: 'round-button',
  771. });
  772. });
  773. }
  774. },
  775. created: function () {
  776. var _self = this;
  777. var clientId = localStorage.getItem("clientId");
  778. if (clientId != null && clientId != '') {
  779. _self.clientId = clientId;
  780. }
  781. console.log('DataSync Vue实例创建完成');
  782. },
  783. mounted: function () {
  784. var _self = this;
  785. if(!plugin.urlApi.getApiUrl()){
  786. const ip = Common.getRootPath();
  787. // const ip = 'http://b374733e.natappfree.cc'
  788. localStorage.setItem("ipServer", ip);
  789. } else {
  790. localStorage.setItem("ipServer", plugin.urlApi.getApiUrl());
  791. }
  792. _self.initData();
  793. console.log('DataSync页面加载完成');
  794. // 隐藏页面加载指示器
  795. setTimeout(function() {
  796. var loadingElement = document.getElementById('pageLoading');
  797. if (loadingElement) {
  798. loadingElement.style.display = 'none';
  799. }
  800. }, 100);
  801. }
  802. });