智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /**
  2. * API 封装模块
  3. * 提供与后端API的交互功能
  4. */
  5. class BIAPIClient {
  6. constructor(baseURL = '') {
  7. this.baseURL = baseURL || window.location.origin;
  8. }
  9. // 通用请求方法
  10. async request(endpoint, options = {}) {
  11. const url = `${this.baseURL}${endpoint}`;
  12. const defaultOptions = {
  13. headers: {
  14. 'Content-Type': 'application/json',
  15. },
  16. ...options,
  17. };
  18. try {
  19. const response = await fetch(url, defaultOptions);
  20. if (!response.ok) {
  21. throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  22. }
  23. return await response.json();
  24. } catch (error) {
  25. console.error('API请求失败:', error);
  26. throw error;
  27. }
  28. }
  29. // GET请求
  30. async get(endpoint, params = {}) {
  31. const url = new URL(`${this.baseURL}${endpoint}`, window.location.origin);
  32. Object.keys(params).forEach(key => {
  33. if (params[key] !== undefined && params[key] !== null) {
  34. url.searchParams.append(key, params[key]);
  35. }
  36. });
  37. return this.request(url.pathname + url.search);
  38. }
  39. // POST请求
  40. async post(endpoint, data = {}) {
  41. return this.request(endpoint, {
  42. method: 'POST',
  43. body: JSON.stringify(data),
  44. });
  45. }
  46. // PUT请求
  47. async put(endpoint, data = {}) {
  48. return this.request(endpoint, {
  49. method: 'PUT',
  50. body: JSON.stringify(data),
  51. });
  52. }
  53. // DELETE请求
  54. async delete(endpoint) {
  55. return this.request(endpoint, {
  56. method: 'DELETE',
  57. });
  58. }
  59. // BI相关API
  60. async getOverviewDashboards() {
  61. return this.get('/bi-api/dashboards/overview');
  62. }
  63. async getDashboardData(dashboardId) {
  64. return this.get(`/bi-api/dashboards/${dashboardId}/data`);
  65. }
  66. async getChartData(chartId) {
  67. return this.get(`/bi-api/charts/${chartId}/data`);
  68. }
  69. async searchBIObjects(keyword) {
  70. return this.get('/bi-api/search', { keyword });
  71. }
  72. async getChartTypes() {
  73. return this.get('/bi-api/charts/types');
  74. }
  75. async getDataSourceTypes() {
  76. return this.get('/bi-api/data-sources/types');
  77. }
  78. async getPopularTags() {
  79. return this.get('/bi-api/popular-tags');
  80. }
  81. async getQuickStats() {
  82. return this.get('/bi-api/quick-stats');
  83. }
  84. async getChartSuggestions() {
  85. return this.get('/bi-api/chart-suggestions');
  86. }
  87. }
  88. // 创建全局API客户端实例
  89. const apiClient = new BIAPIClient();
  90. /**
  91. * 数据获取函数
  92. */
  93. // 获取概览看板列表
  94. export async function getDashboards() {
  95. try {
  96. return await apiClient.getOverviewDashboards();
  97. } catch (error) {
  98. console.error('获取看板列表失败:', error);
  99. throw error;
  100. }
  101. }
  102. // 获取看板详细数据
  103. export async function getDashboardDetail(dashboardId) {
  104. try {
  105. return await apiClient.getDashboardData(dashboardId);
  106. } catch (error) {
  107. console.error(`获取看板 ${dashboardId} 数据失败:`, error);
  108. throw error;
  109. }
  110. }
  111. // 获取图表数据
  112. export async function getChartData(chartId) {
  113. try {
  114. return await apiClient.getChartData(chartId);
  115. } catch (error) {
  116. console.error(`获取图表 ${chartId} 数据失败:`, error);
  117. throw error;
  118. }
  119. }
  120. // 搜索BI对象
  121. export async function searchBIObjects(keyword) {
  122. try {
  123. return await apiClient.searchBIObjects(keyword);
  124. } catch (error) {
  125. console.error(`搜索 ${keyword} 失败:`, error);
  126. throw error;
  127. }
  128. }
  129. // 获取支持的图表类型
  130. export async function getChartTypes() {
  131. try {
  132. return await apiClient.getChartTypes();
  133. } catch (error) {
  134. console.error('获取图表类型失败:', error);
  135. throw error;
  136. }
  137. }
  138. // 获取支持的数据源类型
  139. export async function getDataSourceTypes() {
  140. try {
  141. return await apiClient.getDataSourceTypes();
  142. } catch (error) {
  143. console.error('获取数据源类型失败:', error);
  144. throw error;
  145. }
  146. }
  147. // 获取热门标签
  148. export async function getPopularTags() {
  149. try {
  150. return await apiClient.getPopularTags();
  151. } catch (error) {
  152. console.error('获取热门标签失败:', error);
  153. throw error;
  154. }
  155. }
  156. // 获取快速统计信息
  157. export async function getQuickStats() {
  158. try {
  159. return await apiClient.getQuickStats();
  160. } catch (error) {
  161. console.error('获取快速统计失败:', error);
  162. throw error;
  163. }
  164. }
  165. // 获取图表建议
  166. export async function getChartSuggestions() {
  167. try {
  168. return await apiClient.getChartSuggestions();
  169. } catch (error) {
  170. console.error('获取图表建议失败:', error);
  171. throw error;
  172. }
  173. }
  174. /**
  175. * 工具函数
  176. */
  177. // 格式化日期
  178. export function formatDate(dateString) {
  179. const date = new Date(dateString);
  180. return date.toLocaleString('zh-CN', {
  181. year: 'numeric',
  182. month: '2-digit',
  183. day: '2-digit',
  184. hour: '2-digit',
  185. minute: '2-digit'
  186. });
  187. }
  188. // 格式化数字
  189. export function formatNumber(num, decimals = 2) {
  190. return parseFloat(num).toFixed(decimals);
  191. }
  192. // 显示加载状态
  193. export function showLoading(element) {
  194. element.innerHTML = '<div class="loading">加载中...</div>';
  195. }
  196. // 显示错误状态
  197. export function showError(element, message) {
  198. element.innerHTML = `<div class="error">${message}</div>`;
  199. }
  200. // 显示空状态
  201. export function showEmpty(element, message = '暂无数据') {
  202. element.innerHTML = `<div class="empty">${message}</div>`;
  203. }
  204. // 防抖函数
  205. export function debounce(func, wait) {
  206. let timeout;
  207. return function executedFunction(...args) {
  208. const later = () => {
  209. clearTimeout(timeout);
  210. func(...args);
  211. };
  212. clearTimeout(timeout);
  213. timeout = setTimeout(later, wait);
  214. };
  215. }
  216. // 节流函数
  217. export function throttle(func, limit) {
  218. let inThrottle;
  219. return function() {
  220. const args = arguments;
  221. const context = this;
  222. if (!inThrottle) {
  223. func.apply(context, args);
  224. inThrottle = true;
  225. setTimeout(() => inThrottle = false, limit);
  226. }
  227. };
  228. }